【问题标题】:ForceUpdateSize ListView issue on iOSiOS 上的 ForceUpdateSize ListView 问题
【发布时间】:2018-06-19 09:27:01
【问题描述】:

我有一个使用带有单选按钮的自定义 ViewCells 的自定义 ListView。单击每个单选按钮时,ListView 会动态调整其高度以隐藏/显示评论框。

在 iOS 平台中使用 ForceUpdateSize 时,单击单选按钮时 ListView 的性能会迅速下降。应用最终挂起并停止响应。

是否有替代解决方案可以代替 ForceUpdateSize 在运行时动态扩展 ListView 行?

【问题讨论】:

标签: ios listview xamarin xamarin.forms custom-renderer


【解决方案1】:

在需要更改 ViewCell 大小的任何位置定义 ViewCell Size Change 事件

public static event Action ViewCellSizeChangedEvent; 

在您的情况下,它应该由您的单选按钮触发。像这样称呼它:

ViewCellSizeChangedEvent?.Invoke();

然后它将使用 ListView 渲染器来更新 iOS TableView。

public class CustomListViewRenderer : ListViewRenderer
{
    public CustomListViewRenderer()
    {
        WhatEverContentView.ViewCellSizeChangedEvent += UpdateTableView;
    }

    private void UpdateTableView()
    {
        var tv = Control as UITableView;
        if (tv == null) return;
        tv.BeginUpdates();
        tv.EndUpdates();
    }
}

它应该可以解决您的性能问题,同时继续使用您的 Xaml,而不是创建不需要的自定义 ViewCell。

【讨论】:

  • 您能解释一下为什么BeginUpdatesEndUpdates 修复了性能问题吗?我以为它们被用于单元格动画。
  • 我无法确定,但标准的 xamarin.ios 单元格大小调整似乎是动画的。当我更改大小时,默认情况下视单元会为线性折叠/展开动画
  • 天啊,你无法想象我花了多少时间检查这个。没有任何效果,直到我看到这个。唷,谢谢杜克。顺便说一句,如果您不想使用静态事件,您可以设置一个新属性,例如 NeedsLayout 或在渲染器的 OnElementPropertyChanged() 方法中调用的任何内容。
【解决方案2】:

我的解决方案是:尝试使用自定义渲染器。单击按钮时,我使用 tableView.ReloadRows() 动态更改单元格的大小。

首先,定义一个布尔列表,其项目等于要在源中显示的行。我第一次用 false 初始化它的项目。

List<bool> isExpanded = new List<bool>();

public MyListViewSource(MyListView view)
{
    //It depends on how many rows you want to show.
    for (int i=0; i<10; i++) 
    {
        isExpanded.Add(false);
    }
}

其次,构造GetCell事件(我只是在我的Cell中放置了一个UISwitch进行测试),如:

public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{

    MyListViewCell cell = tableView.DequeueReusableCell("Cell") as MyListViewCell;

    if (cell == null)
    {
        cell = new MyListViewCell(new NSString("Cell"));

        //This event is constructed in my Cell, when the switch's value changed it will be fired.
        cell.RefreshEvent += (refreshCell, isOn) =>
        {
            NSIndexPath index = tableView.IndexPathForCell(refreshCell);
            isExpanded[index.Row] = isOn;
            tableView.ReloadRows(new NSIndexPath[] { index }, UITableViewRowAnimation.Automatic);
        };
    }

    cell.switchBtn.On = isExpanded[indexPath.Row];

    return cell;
}

最后,我们可以覆盖 GetHeightForRow 事件。根据 isExpanded 中的项目设置大值或小值:

public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
    if (isExpanded[indexPath.Row])
    {
        return 80;
    }
    return 40;
}

这是我的牢房的一部分供您参考:

//When switch's value changed, this event will be called
public delegate void RefreshHanle(MyListViewCell cell, bool isOn);
public event RefreshHanle RefreshEvent;
switchBtn.AddTarget((sender, args) =>
{
    UISwitch mySwitch = sender as UISwitch;
    RefreshEvent(this, mySwitch.On);
}, UIControlEvent.ValueChanged);

【讨论】:

  • 我的列表视图是一个跨平台的控件。它在android中运行良好。上面这个解决方案可以应用到ios自定义listview渲染器吗?
  • @Apurva19 是的,我为 listview 做了一个渲染器来做这个。
  • @Land 谢谢,我试试你的解决方案并回复。
  • @Land 你能告诉我应该在哪里添加你给出的 RefreshEvent 事件处理程序代码。我对它有点困惑。在我的例子中,我使用了绑定到视图模型中命令的单选按钮图像。
  • @Apurva19 我在我的自定义单元格中创建了这个刷新事件,当切换按钮的值发生变化时,它将被调用。如果您仍然对此感到困惑,我可以为您制作样品。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多