Xamarin窗体ListView IOS中的交替行颜色

本文关键字:颜色 窗体 ListView IOS Xamarin | 更新日期: 2023-09-27 18:26:17

我正在尝试编写一个CustomRenderer,它可以允许ListView具有交替的行颜色。我遇到了一个问题,不确定这是否是一个错误,或者我只是没有正确实现渲染器:

我对以下代码的期望是,每个自定义视图单元格都应该根据其位置获得一种颜色。然而,事实并非如此,我认为这段代码tv.IndexPathForCell(cell).Row应该返回单元格的索引,但它并没有按预期工作。它目前正在返回一个null值(如果单元格不在部分视图中,它应该返回null值),但我认为该单元格是表视图的一部分,因此也是我的问题。如果我注释掉var index = tv.IndexPathForCell(cell).Row;,然后将背景色设置为静态值,则代码和视图可以正常工作。此外,由于null值而引发异常,并且单元格被设置为基础,视图使用默认背景进行渲染。

我做错了什么吗?我试过其他几件事,但我相信这应该是正确的做法。

c#代码:

[assembly: ExportRenderer(typeof(CustomViewCell), typeof(CustomViewCellRenderer))]

namespace AIM.iOS {
  class CustomViewCellRenderer : ViewCellRenderer {
    public override UITableViewCell GetCell(Cell item, UITableView tv) {
       UITableViewCell cell;
       try {
          cell = base.GetCell(item, tv);
          var customCell = (CustomViewCell)item;
          var cell = base.GetCell(item, tv);
          var index = tv.IndexPathForCell(cell).Row;
          cell.BackgroundColor = (index % 2 == 0) ? Color.Gray.ToUIColor() :
                                                  Color.White.ToUIColor();
       }catch (Exception ex){
          string message = ex.Message;
          cell = base.GetCell(item, tv);
       }
       return cell  
    }
  }
}

我正在扩展Xamarin Forms Labs中的ExtendedViewCell类,它为ViewCell对象添加了背景属性。

namespace AIMUI.Controls {
  public class CustomViewCell : ExtendedViewCell {
    public CustomViewCell() { }
  }
}

这是Xaml:

<localcontrols:ListView>
  <ListView.ItemTemplate>
    <DataTemplate>
      <localcontrols:CustomViewCell>
        <localcontrols:CustomViewCell.View>
        </localcontrols:CustomViewCell.View>
      </localcontrols:CustomViewCell>
    </DataTemplate>
  </ListView.ItemTemplate>
</localcontrols:ListView>

编辑:

好的,所以我通过使用var index = tv.IndexPathForRowAtPoint(cell.Center).Row;解决了获取索引的问题,但是这导致了另一个问题。它第一次工作非常完美,也可以从子视图返回页面。然而,当我离开页面,从masterpage转到另一个视图并返回时,它会将所有项目的背景设置为灰色。目前,我正在创建一个新页面,然后从菜单中将其设置为masterpage.details

Xamarin窗体ListView IOS中的交替行颜色

这可以使用转换器而不是渲染器来完成。

public class StripedBackgroundIndexConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null || parameter == null) return Color.White;
        var index = ((ListView) parameter).ItemsSource.Cast<object>().ToList().IndexOf(value);
        return index % 2 == 0 ? Color.White : Color.FromRgb(240, 240, 240);
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

然后命名您的ListView,并使用x:Reference 将其作为参数传递

<ListView x:Name="MyItemsListView" ItemsSource="{Binding MyItems}" SelectedItem="{Binding SelectedMyItem, Mode=TwoWay}">
<ListView.ItemTemplate>
  <DataTemplate>
    <ViewCell>
      <Grid BackgroundColor="{Binding .,Converter={StaticResource StripedBackgroundIndexConverter}, ConverterParameter={x:Reference MyItemsListView}}">
      </Grid>
    </ViewCell>
  </DataTemplate>
</ListView.ItemTemplate>

当然,如果需要自定义其他元素,也可以在渲染器中使用转换器。

正如您已经发现的那样,IndexPathForRowAtPoint将返回数据源Row的索引,即使该行不可见,这与IndexPathForCell不同,它在单元格可见之前不会正常工作。

关于您的导航问题,当您页面推送到Xamarin.Forms navigation Stack时,它们不会被卸载,并且仍然在后台运行。这就是为什么当您导航回Navigation StackPop时,您看到的页面与您导航离开的页面完全相同(当然,除非您在page事件处理程序中有一些逻辑,它将被重新调用以执行其他处理)。

iOS中,单元格在适当的时候被EnqueuedDequeued并且可能仍然驻留在内存中,尽管它们不可见,等待垃圾回收

这听起来很奇怪,当你离开页面(而不是子视图),然后回到这个页面时,由于你使用的模数,它不起作用。

作为替代方案,仅用于探索和测试,在您的模型中引入另一个字段,该字段具有递增的ID,您对其执行模数以设置行的背景色,以查看是否可以隔离IndexPathForRowAtPoint函数,这可能是主要问题所在。

如果你能创建一个只有这个的小项目,这对那些进一步帮助的人会很有帮助吗?

在联系Xamarin支持并得到他们的帮助后,结果就是这样。

indexPathForPoint基于实际单元格在屏幕上的方式和时间是不可靠的。通常,GetCell方法具有可靠的NSIndexPath参数,但Forms抽象不会传递此参数。

建议作为增强HERE

作为一种变通方法,您可以使用另一种方法进行索引。然而,这对我来说并不奏效,因为它不是100%可靠的。我没有找到实现此功能的好方法。

附带说明-我觉得这在Xamarin代码设计过程中被忽略了,简单地获取每个单元格的索引应该不会那么难。