简体   繁体   English

Xamarin表单ListView IOS中的交替行颜色

[英]Alternating Row Colors in Xamarin Forms ListView IOS

I am trying to write a CustomRenderer that can allow a ListView to have alternating row colors. 我正在尝试编写一个CustomRenderer,它可以允许ListView具有交替的行颜色。 I have run into an issues and am not sure if it might be a bug or am I just not implementing the renderer correctly: 我遇到了一个问题,不确定是不是Bug,或者我只是没有正确实现渲染器:

My expectations for the following code is that each custom view cell should get a color based on it position. 我对以下代码的期望是,每个自定义视图单元格应根据其位置获得颜色。 However, this is not what is happening, I believe that this this code tv.IndexPathForCell(cell).Row should return the cell's index but it is not working as expected. 但是,这不是正在发生的事情,我相信这段代码tv.IndexPathForCell(cell).Row应该返回单元格的索引,但是它没有按预期工作。 It is currently returning a null value ( which it should if the cell in not part view), but I believe that the cell is part of the table view and thus my issue. 它当前正在返回一个空值(如果单元格不在部分视图中,则应该返回一个空值),但是我认为该单元格是表视图的一部分,因此是我的问题。 If I comment out the var index = tv.IndexPathForCell(cell).Row; 如果我注释掉var index = tv.IndexPathForCell(cell).Row; and then set the background color to a static value the code and view works correctly. 然后将背景色设置为静态值,代码和视图即可正常工作。 In addition an exception is thrown because of the null value and the cell is set to the base and the view renders with a default background. 另外,由于null值而引发异常,并且该单元格设置为基础,并且视图使用默认背景进行渲染。

Am I doing something wrong, I have tried several other things but I believe this should be the correct way to do this. 我在做错什么吗,我尝试了其他几件事,但是我认为这应该是正确的方法。

c# code: 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  
    }
  }
}

I am extending the ExtendedViewCell class from Xamarin-Forms-Labs which adds background properties to the ViewCell object. 我正在从Xamarin-Forms-Labs扩展ExtendedViewCell类,该类将背景属性添加到ViewCell对象。

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

Here is the Xaml: 这是Xaml:

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

Edit: 编辑:

Ok, so I solved the issue with getting the index by using var index = tv.IndexPathForRowAtPoint(cell.Center).Row; 好的,所以我通过使用var index = tv.IndexPathForRowAtPoint(cell.Center).Row;获得索引来解决了这个问题var index = tv.IndexPathForRowAtPoint(cell.Center).Row; , however this has caused another issue. ,但这引起了另一个问题。 It works perfectly the first time, as well as coming back to the page from a sub view. 它在第一次运行时完美无缺,并且可以从子视图返回页面。 However, when I leave the page and go to another view from the masterpage and come back it sets the background of all items gray. 但是,当我离开页面并从masterpage页面转到另一个视图并返回时,它将所有项目的背景设置为灰色。 Currently, I am creating a new page and then setting it to the masterpage.details , when coming from the menu. 当前,我正在创建一个新页面,然后从菜单中将其设置为masterpage.details

This can be done using a converter instead of a renderer. 可以使用转换器而不是渲染器来完成。

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();
    }
}

Then name your ListView and pass it as the parameter using x:Reference 然后命名您的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>

Of course you can also use the converter in your renderer if you are needing to customize other elements. 当然,如果需要自定义其他元素,也可以在渲染器中使用转换器。

As you've already found out IndexPathForRowAtPoint will return the index of the Row in the datasource even if the row isn't visible , unlike the IndexPathForCell that will not work correctly until the cell is visible. 正如你已经发现了IndexPathForRowAtPoint将返回的索引数据源中,即使该行是不可见的 ,不像IndexPathForCell直到细胞是可见的,将无法正常工作。

With regard to your navigation issue, when you Push pages onto the Xamarin.Forms Navigation Stack they are not unloaded and still are functional behind the scenes. 关于你的导航问题,当你按下页面到Xamarin.Forms导航堆栈他们卸载,仍是幕后的功能。 This is why when you navigate back through the Navigation Stack and Pop one off, you are seeing the same page exactly the same as you had navigated away from it (unless of course you have some logic in one of the Page event-handlers that will get re-invoked doing something other processing). 这就是为什么当您在导航堆栈导航弹出一个页面时,会看到与离开该页面时完全相同的页面原因(除非您在其中一个页面 事件处理程序中有一定的逻辑,重新调用以进行其他处理)。

In iOS the cells are Enqueued and Dequeued when appropriate, and may still reside in memory although they are not visible, awaiting Garbage Collection . iOS系统中的细胞进行排队 ,并已出列在适当的时候,并可能仍驻留在内存中,尽管它们是不可见的,等待垃圾回收

It sounds very weird behavior that when you navigate away from the page ( not to a subview ) and then come back to this page, that it doesn't work, due to the modulus that you are using. 听起来很奇怪,当您离开页面( 而不是子视图 )然后返回此页面时,由于使用的模数 ,它不起作用。

As an alternative, just for exploration and testing purposes , introduce another field into your Model that has an increasing ID that you do the modulus on to set the background-color of the row, to see if you can isolate the IndexPathForRowAtPoint function being possibly where the main issue is. 或者, 仅出于探索和测试目的 ,在您的模型中引入另一个具有递增ID的字段,您可以对它进行模数设置以设置行的背景色,以查看是否可以隔离 IndexPathForRowAtPoint函数,主要问题是。

If you able to create a small project with only this in, it would be very helpful for those in assisting further? 如果您能够仅以此创建一个小型项目,那么对于那些进一步协助的人将非常有帮助?

After contacting Xamarin Support, and with their help this was the result. 与Xamarin支持人员联系后,在他们的帮助下,这就是结果。

indexPathForPoint is not reliable based on how and when the actual cell is on the screen. 根据实际单元格在屏幕上的显示方式和时间,indexPathForPoint是不可靠的。 Typically, the GetCell method has the NSIndexPath parameter which is reliable, but the Forms abstraction does not pass this along. 通常,GetCell方法具有可靠的NSIndexPath参数,但Forms抽象不会传递此参数。

Suggested as an enhancement HERE 建议作为增强HERE

As a workaround, you could use another method for index. 解决方法是,可以使用其他方法进行索引。 However, this did not worked for me, as it was not 100% reliable. 但是,这对我没有用,因为它不是100%可靠的。 I did not find a great way to implement this functionality. 我没有找到实现此功能的好方法。

As a side note - I feel that this was over looked in the Xamarin code design process, It should not be this hard to simply get the index of each cell. 附带说明 -我觉得在Xamarin代码设计过程中已经忽略了这一点,简单地获取每个单元格的索引应该不难。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM