2

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

我对以下代码的期望是每个自定义视图单元格都应该根据其位置获得颜色。但是,这不是正在发生的事情,我相信这段代码tv.IndexPathForCell(cell).Row应该返回单元格的索引,但它没有按预期工作。它目前正在返回一个空值(如果单元格不是部分视图,它应该返回),但我相信该单元格是表格视图的一部分,因此是我的问题。如果我注释掉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>

编辑:

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

4

3 回答 3

2

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

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>

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

于 2016-02-23T21:19:41.647 回答
1

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

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

iOS中,单元格在适当的时候被EnqueuedDequeued,尽管它们不可见,但仍可能驻留在内存中,等待Garbage Collection

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

作为替代方案,仅出于探索和测试目的,将另一个字段引入您的模型中,该字段具有增加的ID,您可以在该字段上进行模数以设置行的背景颜色,以查看是否可以隔离IndexPathForRowAtPoint函数可能在哪里主要问题是。

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

于 2014-10-11T00:32:22.453 回答
0

在联系 Xamarin 支持后,在他们的帮助下,这就是结果。

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

建议作为增强HERE

作为一种解决方法,您可以使用另一种方法进行索引。但是,这对我不起作用,因为它不是 100% 可靠的。我没有找到实现此功能的好方法。

作为旁注- 我觉得这在 Xamarin 代码设计过程中被忽略了,简单地获取每个单元格的索引应该不难。

于 2014-10-15T14:53:46.360 回答