Xamarin.Forms ListView:设置点击项目的高亮颜色

使用Xamarin.Forms ,我怎样才能定义一个选定的/点击ListView项目的高亮/背景颜色?

(我的列表有一个黑色的背景和白色的文本颜色,所以iOS上的默认高亮颜色太亮了,而在Android上却没有高亮显示 – 直到细微的水平灰线。

示例:(左:iOS,右:Android;按“Barn2”)

Solutions Collecting From Web of "Xamarin.Forms ListView:设置点击项目的高亮颜色"

看起来实际上有一个跨平台的方式来做到这一点,在iOS和Android(不知道有关Windows)的作品。 它只使用绑定,并不需要自定义渲染器(这似乎很less见)。 这是一个大量使用Google的混搭,所以感谢任何我可能借来的人…

我假设ViewCells,但这应该也适用于文本或图像单元格。 我只在这里包括典型的文字,图片等相关代码

在你的页面上做这样的事情:

MyModel model1 = new MyModel(); MyModel model2 = new MyModel(); ListView list = new ListView { ItemsSource = new List<MyModel> { model1, model2 }; ItemTemplate = new DataTemplate( typeof(MyCell) ) }; 

您的自定义模型可能如下所示:

 public class MyModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private Color _backgroundColor; public Color BackgroundColor { get { return _backgroundColor; } set { _backgroundColor = value; if ( PropertyChanged != null ) { PropertyChanged( this, new PropertyChangedEventArgs( "BackgroundColor" ) ); } } } public void SetColors( bool isSelected ) { if ( isSelected ) { BackgroundColor = Color.FromRgb( 0.20, 0.20, 1.0 ); } else { BackgroundColor = Color.FromRgb( 0.95, 0.95, 0.95 ); } } } 

那么对于你的ItemTemplate,你需要一个像这样的自定义单元类:

 public class MyCell : ViewCell { public MyCell() : base() { RelativeLayout layout = new RelativeLayout(); layout.SetBinding( Layout.BackgroundColorProperty, new Binding( "BackgroundColor" ) ); View = layout; } } 

然后在你的ItemSelected事件处理程序中,执行以下操作。 请注意,“selected”是MyModel的一个实例,用于跟踪当前select的项目。 我只在这里显示背景颜色,但我也使用这种技术来反转突出显示文本和细节的文字颜色。

 private void ItemSelected( object sender, ItemTappedEventArgs args ) { // Deselect previous if ( selected != null ) { selected.SetColors( false ); } // Select new selected = (list.SelectedItem as MyModel); selected.SetColors( true ); } 

我有iOS和Android的屏幕截图,如果有人想让我碰到10点,所以我可以发贴:)

在Android中,只需编辑Resources \ Value下的Style.xml文件即可:

 <resources> <style name="MyTheme" parent="android:style/Theme.Material.Light.DarkActionBar"> <item name="android:colorPressedHighlight">@color/ListViewSelected</item> <item name="android:colorLongPressedHighlight">@color/ListViewHighlighted</item> <item name="android:colorFocusedHighlight">@color/ListViewSelected</item> <item name="android:colorActivatedHighlight">@color/ListViewSelected</item> <item name="android:activatedBackgroundIndicator">@color/ListViewSelected</item> </style> <color name="ListViewSelected">#96BCE3</color> <color name="ListViewHighlighted">#E39696</color> </resources> 

iOS版

解:

在自定义ViewCellRenderer您可以设置SelectedBackgroundView 。 只需用你select的背景颜色创build一个新的UIView ,然后设置好。

 public override UITableViewCell GetCell(Cell item, UITableView tv) { var cell = base.GetCell(item, tv); cell.SelectedBackgroundView = new UIView { BackgroundColor = UIColor.DarkGray, }; return cell; } 

结果:

注意:

使用Xamarin.Forms创build一个新的 UIView似乎很重要,而不是只设置当前的背景颜色。


Android的

解:

我在Android上find的解决scheme有点复杂:

  1. Resources > drawable文件夹中创build一个新的可绘制的ViewCellBackground.xml

     <?xml version="1.0" encoding="UTF-8" ?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" > <shape android:shape="rectangle"> <solid android:color="#333333" /> </shape> </item> <item> <shape android:shape="rectangle"> <solid android:color="#000000" /> </shape> </item> </selector> 

    它为UI元素的默认状态和“按下”状态定义了具有不同颜色的实体形状。

  2. ViewCellView使用inheritance的类,例如:

     public class TouchableStackLayout: StackLayout { } 
  3. 为这个类实现一个自定义渲染器来设置背景资源:

     public class ElementRenderer: VisualElementRenderer<Xamarin.Forms.View> { protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e) { SetBackgroundResource(Resource.Drawable.ViewCellBackground); base.OnElementChanged(e); } } 

结果:

我有一个类似的过程,完全跨平台,但我跟踪自己的select状态,我已经做了这个在XAML。

  <ListView x:Name="ListView" ItemsSource="{Binding ListSource}" RowHeight="50"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <ViewCell.View> <ContentView Padding="10" BackgroundColor="{Binding BackgroundColor}"> <Label Text="{Binding Name}" HorizontalOptions="Center" TextColor="White" /> </ContentView> </ViewCell.View> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> 

然后在ItemTapped事件中

  ListView.ItemTapped += async (s, e) => { var list = ListSource; var listItem = list.First(c => c.Id == ((ListItem)e.Item).Id); listItem.Selected = !listItem.Selected; SelectListSource = list; ListView.SelectedItem = null; }; 

正如你所看到的,我只是将ListView.SelectedItem设置为null,以删除任何进入平台的特定select样式。

在我的模型中,我有

  private Boolean _selected; public Boolean Selected { get { return _selected; } set { _selected = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("BackgroundColor")); } } public Color BackgroundColor { get { if (Selected) return Color.Black; else return Color.Blue } } 

我也遇到了同样的问题,我通过为Falkobuild议的iOS创build自定义渲染器来解决这个问题。然而,我避免了Android的样式修改,我想出了一种为Android使用自定义渲染器的方法。

这是一种时髦,如何select标志总是为android视图单元格,这就是为什么我不得不创build一个新的私人财产来跟踪它是假的。 但除此之外,我认为这跟随一个更适当的模式,如果你想在两个平台上使用自定义的渲染器,在我的情况下,我做了它的TextCell,但我相信它适用于其他CellViews相同的方式。

Xamarinforms

 public class CustomTextCell : TextCell { /// <summary> /// The SelectedBackgroundColor property. /// </summary> public static readonly BindableProperty SelectedBackgroundColorProperty = BindableProperty.Create("SelectedBackgroundColor", typeof(Color), typeof(CustomTextCell), Color.Default); /// <summary> /// Gets or sets the SelectedBackgroundColor. /// </summary> public Color SelectedBackgroundColor { get { return (Color)GetValue(SelectedBackgroundColorProperty); } set { SetValue(SelectedBackgroundColorProperty, value); } } } 

iOS版

 public class CustomTextCellRenderer : TextCellRenderer { public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv) { var cell = base.GetCell(item, reusableCell, tv); var view = item as CustomTextCell; cell.SelectedBackgroundView = new UIView { BackgroundColor = view.SelectedBackgroundColor.ToUIColor(), }; return cell; } } 

Android的

 public class CustomTextCellRenderer : TextCellRenderer { private Android.Views.View cellCore; private Drawable unselectedBackground; private bool selected; protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, ViewGroup parent, Context context) { cellCore = base.GetCellCore(item, convertView, parent, context); // Save original background to rollback to it when not selected, // We assume that no cells will be selected on creation. selected = false; unselectedBackground = cellCore.Background; return cellCore; } protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args) { base.OnCellPropertyChanged(sender, args); if (args.PropertyName == "IsSelected") { // I had to create a property to track the selection because cellCore.Selected is always false. // Toggle selection selected = !selected; if (selected) { var customTextCell = sender as CustomTextCell; cellCore.SetBackgroundColor(customTextCell.SelectedBackgroundColor.ToAndroid()); } else { cellCore.SetBackground(unselectedBackground); } } } } 

为了设置高亮项目的颜色,你需要在iOS中设置cell.SelectionStyle的颜色。

这个例子是将被点击的项目的颜色设置为透明。

如果你想要,你可以用UITableViewCellSelectionStyle其他颜色来改变它。 这是通过在Forms项目中创build一个新的自定义ListView渲染器来写入iOS的平台项目。

 public class CustomListViewRenderer : ListViewRenderer { protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (Control == null) { return; } if (e.PropertyName == "ItemsSource") { foreach (var cell in Control.VisibleCells) { cell.SelectionStyle = UITableViewCellSelectionStyle.None; } } } } 

对于android,你可以在你的values / styles.xml中添加这个样式

 <style name="ListViewStyle.Light" parent="android:style/Widget.ListView"> <item name="android:listSelector">@android:color/transparent</item> <item name="android:cacheColorHint">@android:color/transparent</item> </style> 

这是纯粹的跨平台和整洁的方式:

1)定义一个触发器动作

 namespace CustomTriggers { public class DeselectListViewItemAction:TriggerAction<ListView> { protected override void Invoke(ListView sender) { sender.SelectedItem = null; } } } 

2)将以上类实例作为XAML中的EventTrigger操作应用,如下所示

  <ListView x:Name="YourListView" ItemsSource="{Binding ViewModelItems}"> <ListView.Triggers> <EventTrigger Event="ItemSelected"> <customTriggers:DeselectListViewItemAction></customTriggers:DeselectListViewItemAction> </EventTrigger> </ListView.Triggers> </ListView> 

不要忘记添加xmlns:customTriggers="clr-namespace:CustomTriggers;assembly=ProjectAssembly"

注意:由于没有任何项目处于选定模式,所以select样式将不会应用于任一平台。

此解决scheme工作正常,但如果您将ListView的caching策略从默认值更改它停止工作。 它工作,如果你新的你的ListView像这样: listView = new ListView() { ... }; 但是,如果你这样做,它不起作用(背景对于所选项目保持灰色): listView = new ListView(cachingStrategy:ListViewCachingStrategy.RecycleElement) { ... };

以下是即使使用非标准的cachingStrategy也能运行的解决scheme。 我更喜欢这样的其他解决scheme,如有OnItemSelected方法中的代码,与ViewModel绑定为背景颜色。

感谢@Lang_tu_bi_dien,他们在这里发布了这个想法: Listview Selected Item Background Color

最终的代码如下所示:

Xamarin.Forms代码:

 namespace MyProject { public class ListView2 : ListView { public ListView2(ListViewCachingStrategy cachingStrategy) : base(cachingStrategy) { } } } 

XAML在您的页面上:

  <ListView2 x:Name="myListView" ListViewCachingStrategy="RecycleElement" ItemsSource="{Binding ListSource}" RowHeight="50"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <ViewCell.View> <Label Text="{Binding Name}" HorizontalOptions="Center" TextColor="White" /> </ContentView> </ViewCell.View> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView2>