简体   繁体   English

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

[英]Xamarin.Forms ListView: Set the highlight color of a tapped item

Using Xamarin.Forms , how can I define the highlight/background color of a selected/tapped ListView item?使用Xamarin.Forms ,如何定义选定/点击的 ListView 项目的突出显示/背景颜色?

(My list has a black background and white text color, so the default highlight color on iOS is too bright. In contrast, on Android there is no highlighting at all - up to a subtle horizontal gray line.) (我的列表有黑色背景和白色文本颜色,所以 iOS 上的默认突出显示颜色太亮了。相比之下,Android 上根本没有突出显示 - 直到一条微妙的水平灰线。)

Example: (left: iOS, right: Android; while pressing "Barn2")示例:(左:iOS,右:Android;同时按“Barn2”)

In Android simply edit your styles.xml file under Resources\\values adding this:在 Android 中,只需在 Resources\\values 下编辑您的 styles.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>

It looks like there is actually a cross-platform way to do this that works on both iOS and Android (not sure about Windows).看起来实际上有一种跨平台的方式可以在iOS和Android上运行(不确定Windows)。 It uses only binding and does not require custom renderers (which seems rare).它只使用绑定,不需要自定义渲染器(这似乎很少见)。 This is a mash-up of lots of googling, so thanks to anyone who I may have borrowed from...这是大量谷歌搜索的混搭,所以感谢任何我可能借用的人......

I am assuming ViewCells, but this should work for Text or Image cells as well.我假设使用 ViewCells,但这也适用于文本或图像单元格。 I am only including the relevant code here beyond the typical text, image, etc.除了典型的文本、图像等,我只在此处包含相关代码。

On your page do something like this:在你的页面上做这样的事情:

MyModel model1 = new MyModel();
MyModel model2 = new MyModel();

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

Your custom Model might look something like this:您的自定义模型可能如下所示:

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

Then for your ItemTemplate you need a custom cell class something like this:然后对于你的 ItemTemplate 你需要一个像这样的自定义单元类:

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

        View = layout;
    }
}

Then in your ItemSelected event handler, do the following.然后在您的 ItemSelected 事件处理程序中,执行以下操作。 Note that 'selected' is an instance of MyModel used to track the currently selected item.请注意,'selected' 是用于跟踪当前所选项目的 MyModel 实例。 I am only showing background color here, but I also use this technique to reverse highlight the text and detail text colors.我在这里只显示背景颜色,但我也使用这种技术来反向突出显示文本和细节文本颜色。

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 IOS

Solution:解决方案:

Within a custom ViewCellRenderer you can set the SelectedBackgroundView .在自定义ViewCellRenderer您可以设置SelectedBackgroundView Simply create a new UIView with a background color of your choice and you're set.只需使用您选择的背景颜色创建一个新的UIView

public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
    var cell =  base.GetCell(item, reusableCell, tv);

    cell.SelectedBackgroundView = new UIView {
        BackgroundColor = UIColor.DarkGray,
    };

    return cell;
}

Result:结果:

Note:笔记:

With Xamarin.Forms it seems to be important to create a new UIView rather than just setting the background color of the current one.使用 Xamarin.Forms 创建一个新的UIView而不是仅仅设置当前UIView的背景颜色似乎很重要。


Android安卓

Solution:解决方案:

The solution I found on Android is a bit more complicated:我在 Android 上找到的解决方案有点复杂:

  1. Create a new drawable ViewCellBackground.xml within the Resources > drawable folder:Resources > drawable文件夹中创建一个新的可绘制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>

    It defines solid shapes with different colors for the default state and the "pressed" state of a UI element.它为 UI 元素的默认状态和“按下”状态定义了具有不同颜色的实心形状。

  2. Use a inherited class for the View of your ViewCell , eg:ViewCellView使用继承的类,例如:

     public class TouchableStackLayout: StackLayout { }
  3. Implement a custom renderer for this class setting the background resource:为此类设置背景资源实现自定义渲染器:

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

Result:结果:

To change color of selected ViewCell , there is a simple process without using custom renderer.要更改所选ViewCell颜色,有一个简单的过程,无需使用自定义渲染器。 Make Tapped event of your ViewCell as below使Tapped您的事件ViewCell如下

<ListView.ItemTemplate>
    <DataTemplate>
        <ViewCell Tapped="ViewCell_Tapped">            
        <Label Text="{Binding StudentName}" TextColor="Black" />
        </ViewCell>
    </DataTemplate>
</ListView.ItemTemplate>

In your ContentPage or .cs file, implement the event在您的 ContentPage 或 .cs 文件中,实现事件

private void ViewCell_Tapped(object sender, System.EventArgs e)
{
    if(lastCell!=null)
    lastCell.View.BackgroundColor = Color.Transparent;
    var viewCell = (ViewCell)sender;
    if (viewCell.View != null)
    {
        viewCell.View.BackgroundColor = Color.Red;
        lastCell = viewCell;
    }
} 

Declare lastCell at the top of your ContentPage like this ViewCell lastCell;ContentPage的顶部声明lastCell就像这个ViewCell lastCell;

Only for Android仅适用于安卓

Add in your custom theme or your default theme under ProjectName.Android/Resources/values/styles.xmlProjectName.Android/Resources/values/styles.xml下添加自定义主题或默认主题

<item name="android:colorActivatedHighlight">@android:color/transparent</item>

I have a similar process, completely cross platform, however I track the selection status myself and I have done this in XAML.我有一个类似的过程,完全跨平台,但是我自己跟踪选择状态,并且我已经在 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>

Then in the ItemTapped Event然后在 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;
};

As you can see I just set the ListView.SelectedItem to null to remove any of the platform specific selection styles that come into play.如您所见,我只是将 ListView.SelectedItem 设置为 null 以删除任何平台特定的选择样式。

In my model I have在我的模型中,我有

private Boolean _selected;

public Boolean Selected
{
    get => _selected;
    set
    {
        _selected = value;
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs("BackgroundColor"));
    }
}

public Color BackgroundColor
{
    get => Selected ? Color.Black : Color.Blue;
}

I had this same issue and I solved it as well by creating a custom renderer for iOS as Falko suggests, however, I avoided the styles modification for Android, I figured out a way to use a custom renderer for Android as well.我遇到了同样的问题,我也按照 Falko 的建议通过为 iOS 创建自定义渲染器来解决它,但是,我避免了对 Android 的样式修改,我还想出了一种为 Android 使用自定义渲染器的方法。

It is kind of funky how the selected flag is always false for the android view cell that's why I had to create a new private property to track it.对于 android 视图单元格,所选标志始终为 false 的方式有点奇怪,这就是为什么我必须创建一个新的私有属性来跟踪它。 but other than that I think this follows a more appropriate pattern if you want to use custom renderers for both platforms, In my case I did it for TextCell but I believe it applies the same way for other CellViews.但除此之外,如果您想为两个平台使用自定义渲染器,我认为这遵循更合适的模式,在我的情况下,我为 TextCell 做了它,但我相信它适用于其他 CellViews 的方式相同。

Xamarin Forms Xamarin 表单

using Xamarin.Forms;

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

...then, in the .xaml page, you need to add an XMLNS reference back to the new CustomViewCell... ...然后,在 .xaml 页面中,您需要将 XMLNS 引用添加回新的 CustomViewCell ...

xmlns:customuicontrols="clr-namespace:MyMobileApp.CustomUIControls"

And don't forget to make actual use of the new Custom comtrol in your XAML.并且不要忘记在 XAML 中实际使用新的自定义控件。

Here is the purely cross platform and neat way:这是纯粹的跨平台和简洁的方式:

1) Define a trigger action 1) 定义触发动作

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

2) Apply the above class instance as an EventTrigger action in XAML as below 2) 将上面的类实例应用为 XAML 中的 EventTrigger 操作,如下所示

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

Don't forget to add xmlns:customTriggers="clr-namespace:CustomTriggers;assembly=ProjectAssembly"不要忘记添加xmlns:customTriggers="clr-namespace:CustomTriggers;assembly=ProjectAssembly"

Note: Because none of your items are in selected mode, selection styling will not get applied on either of the platforms.注意:由于您的所有项目均未处于选定模式,因此选择样式将不会应用于任一平台。

I have & use a solution similar to @adam-pedley.我有并使用了类似于@adam-pedley 的解决方案。 No custom renderers, in xaml i bind background ViewCell Property没有自定义渲染器,在 xaml 中我绑定了背景 ViewCell 属性

                <ListView x:Name="placesListView" Grid.Row="2" Grid.ColumnSpan="3" ItemsSource="{Binding PlacesCollection}" SelectedItem="{Binding PlaceItemSelected}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid BackgroundColor="{Binding IsSelected,Converter={StaticResource boolToColor}}">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="auto"/>
                                    <RowDefinition Height="auto"/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>

                                <Label Grid.Row="1" Grid.ColumnSpan="2" Text="{Binding DisplayName}" Style="{StaticResource blubeLabelBlackItalic}" FontSize="Default" HorizontalOptions="Start" />
                                <Label Grid.Row="2" Grid.ColumnSpan="2" Text="{Binding DisplayDetail}"  Style="{StaticResource blubeLabelGrayItalic}" FontSize="Small" HorizontalOptions="Start"/>
                                <!--
                                <Label Grid.RowSpan="2" Grid.ColumnSpan="2" Text="{Binding KmDistance}"  Style="{StaticResource blubeLabelGrayItalic}" FontSize="Default" HorizontalOptions="End" VerticalOptions="Center"/>
                                -->
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>                    
            </ListView>

In code (MVVM) i save the lastitemselected by a boolToColor Converter i update background color在代码(MVVM)中,我保存了 boolToColor 转换器选择的最后一项,我更新了背景颜色

    public class BoolToColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? Color.Yellow : Color.White;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (Color)value == Color.Yellow ? true : false;
        }
    }

    PlaceItem LastItemSelected;

    PlaceItem placeItemSelected;
    public PlaceItem PlaceItemSelected
    {
        get
        {
            return placeItemSelected;
        }

        set
        {
            if (LastItemSelected != null)
                LastItemSelected.IsSelected = false;

            placeItemSelected = value;
            if (placeItemSelected != null)
            {
                placeItemSelected.IsSelected = true;
                LastItemSelected = placeItemSelected;
            }
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PlaceItemSelected)));
        }
    }

My example is extracted by a listview of places which are in a Xamarin Forms Maps (same contentpage).我的示例是通过 Xamarin Forms Maps(相同内容页面)中的地点列表视图提取的。 I hope this solution will be usefull for somebody我希望这个解决方案对某人有用

In order to set the color of highlighted item you need to set the color of cell.SelectionStyle in iOS.为了设置突出显示项的颜色,您需要在 iOS 中设置cell.SelectionStyle的颜色。

This example is to set the color of tapped item to transparent.本例是将点击项目的颜色设置为透明。

If you want you can change it with other colors from UITableViewCellSelectionStyle .如果需要,您可以使用UITableViewCellSelectionStyle其他颜色更改它。 This is to be written in the platform project of iOS by creating a new Custom ListView renderer in your Forms project.这将通过在您的 Forms 项目中创建一个新的自定义 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;
                }
            }
        }
    }

For android you can add this style in your values/styles.xml对于 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>

This solution works fine, but if you change the caching strategy of the ListView away from the default value it stops working.此解决方案工作正常,但如果您将 ListView 的缓存策略更改为远离默认值,它将停止工作。 It works if you new up your ListView like this: listView = new ListView() { ... };如果你像这样更新你的 ListView,它会起作用: listView = new ListView() { ... }; But if you do this it does not work (the background stays grey for the selected item): listView = new ListView(cachingStrategy:ListViewCachingStrategy.RecycleElement) { ... };但是如果你这样做它就不起作用(所选项目的背景保持灰色): listView = new ListView(cachingStrategy:ListViewCachingStrategy.RecycleElement) { ... };

Below is a solution that works even with a non-standard cachingStrategy.下面是一个即使使用非标准缓存策略也能工作的解决方案。 I prefer this to other solutions like having code in the OnItemSelected method coupled with a binding from the ViewModel for the background color.与其他解决方案相比,我更喜欢这个解决方案,例如在 OnItemSelected 方法中使用代码以及来自 ViewModel 的背景颜色绑定。

Credit to @Lang_tu_bi_dien who posted the idea here: Listview Selected Item Background Color感谢@Lang_tu_bi_dien 在这里发布了这个想法: Listview Selected Item Background Color

The final code then looks like this:最终代码如下所示:

Xamarin.Forms code: Xamarin.Forms 代码:

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

XAML on your page:您页面上的 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>

iOS-specific renderer: iOS 特定的渲染器:

[assembly: ExportRenderer(typeof(ListView2), typeof(ListView2Renderer))]
namespace MyProject.iOS
{
    public partial class ListView2Renderer : ListViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
        {
            base.OnElementChanged(e);
            if (Control != null && e != null)
            {
                //oldDelegate = (UITableViewSource)Control.Delegate;
                Control.Delegate = new ListView2Delegate(e.NewElement);
            }
        }
    }


    class ListView2Delegate : UITableViewDelegate
    {
        private ListView _listView;

        internal ListView2Delegate(ListView listView)
        {
            _listView = listView;
        }

        public override void WillDisplay(UITableView tableView, UITableViewCell cell, Foundation.NSIndexPath indexPath)
        {
            cell.SelectedBackgroundView = new UIView()
            {
                BackgroundColor = Color.Red.ToUIColor()
            };
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _listView = null;
            }
            base.Dispose(disposing);
        }
    }
}

Note: you may run into some issues due to the fact that you are replacing the default delegate, for more info on this see Setting delegate of control in custom renderer results in lost functionality .注意:由于您要替换默认委托,您可能会遇到一些问题,有关这方面的更多信息,请参阅在自定义渲染器中设置控制委托导致功能丢失 In my project it all works as it should if I do this:在我的项目中,如果我这样做,一切都会正常工作:

  • Use the normal ListView together with the ListItemViewCellRenderer code given in in the earlier posts on this thread for ListViews that use the default caching strategy ListViewCachingStrategy.RetainElement.对于使用默认缓存策略 ListViewCachingStrategy.RetainElement 的 ListView,使用普通 ListView 和本线程之前帖子中给出的 ListItemViewCellRenderer 代码。

  • Use this ListView2 together for ListViews that use a non-default caching strategy ie ListViewCachingStrategy.RecycleElement or ListViewCachingStrategy.RecycleElementAndDataTemplate.将此 ListView2 一起用于使用非默认缓存策略的 ListView,即 ListViewCachingStrategy.RecycleElement 或 ListViewCachingStrategy.RecycleElementAndDataTemplate。

I am also filing a feature request with Xamarin, please upvote it if you feel this should be added to the standard ListView: ListView desperately needs a SelectedItemBackgroundColor property我还向 Xamarin 提交了一个功能请求,如果您认为应该将其添加到标准 ListView 中,请点赞: ListView 迫切需要 SelectedItemBackgroundColor 属性

Found this lovely option using effects here . 在这里使用效果找到了这个可爱的选项。

iOS: IOS:

[assembly: ResolutionGroupName("MyEffects")]
[assembly: ExportEffect(typeof(ListViewHighlightEffect), nameof(ListViewHighlightEffect))]
namespace Effects.iOS.Effects
{
    public class ListViewHighlightEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            var listView = (UIKit.UITableView)Control;

            listView.AllowsSelection = false;
        }

        protected override void OnDetached()
        {
        }
    }
}

Android:安卓:

[assembly: ResolutionGroupName("MyEffects")]
[assembly: ExportEffect(typeof(ListViewHighlightEffect), nameof(ListViewHighlightEffect))]
namespace Effects.Droid.Effects
{
    public class ListViewHighlightEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            var listView = (Android.Widget.ListView)Control;

            listView.ChoiceMode = ChoiceMode.None;
        }

        protected override void OnDetached()
        {
        }
    }
}

Forms:形式:

ListView_Demo.Effects.Add(Effect.Resolve($"MyEffects.ListViewHighlightEffect"));

The easiest way to accomplish this on android is by adding the following code to your custom style :在 android 上完成此操作的最简单方法是将以下代码添加到您的自定义样式:

@android:color/transparent @android:颜色/透明

The easiest way to change the selection color is adding these to your Android.Resources.values.styles更改选择颜色的最简单方法是将这些添加到您的 Android.Resources.values.styles

  <item name="android:colorPressedHighlight">@android:color/holo_blue_bright</item>
  <item name="android:colorFocusedHighlight">@android:color/holo_blue_bright</item>
  <item name="android:colorActivatedHighlight">@android:color/holo_blue_bright</item>

The previous answers either suggest custom renderers or require you to keep track of the selected item either in your data objects or otherwise.先前的答案要么建议自定义渲染器,要么要求您在数据对象或其他方式中跟踪所选项目。 This isn't really required, there is a way to link to the functioning of the ListView in a platform agnostic way.这并不是真正必需的,有一种方法可以以与平台无关的方式链接到ListView的功能。 This can then be used to change the selected item in any way required.然后可以使用它以任何需要的方式更改所选项目。 Colors can be modified, different parts of the cell shown or hidden depending on the selected state.可以修改颜色,根据所选状态显示或隐藏单元格的不同部分。

Let's add an IsSelected property to our ViewCell .让我们一加IsSelected属性我们ViewCell There is no need to add it to the data object;无需将其添加到数据对象中; the listview selects the cell, not the bound data.列表视图选择单元格,而不是绑定数据。

public partial class SelectableCell : ViewCell {

  public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create(nameof(IsSelected), typeof(bool), typeof(SelectableCell), false, propertyChanged: OnIsSelectedPropertyChanged);
  public bool IsSelected {
    get => (bool)GetValue(IsSelectedProperty);
    set => SetValue(IsSelectedProperty, value);
  }

  // You can omit this if you only want to use IsSelected via binding in XAML
  private static void OnIsSelectedPropertyChanged(BindableObject bindable, object oldValue, object newValue) {
    var cell = ((SelectableCell)bindable);
    // change color, visibility, whatever depending on (bool)newValue
  }

  // ...
}

To create the missing link between the cells and the selection in the list view, we need a converter (the original idea came from the Xamarin Forum ):要在列表视图中的单元格和选择之间创建缺失的链接,我们需要一个转换器(最初的想法来自Xamarin 论坛):

public class IsSelectedConverter : IValueConverter {
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
    value != null && value == ((ViewCell)parameter).View.BindingContext;

  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
    throw new NotImplementedException();
}

We connect the two using this converter:我们使用这个转换器连接两者:

<ListView x:Name="ListViewName">
  <ListView.ItemTemplate>
    <DataTemplate>
      <local:SelectableCell x:Name="ListViewCell"
        IsSelected="{Binding SelectedItem, Source={x:Reference ListViewName}, Converter={StaticResource IsSelectedConverter}, ConverterParameter={x:Reference ListViewCell}}" />
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

This relatively complex binding serves to check which actual item is currently selected.这种相对复杂的绑定用于检查当前选择了哪个实际项目。 It compares the SelectedItem property of the list view to the BindingContext of the view in the cell.它将列表视图的SelectedItem属性与单元格中视图的BindingContext进行比较。 That binding context is the data object we actually bind to.该绑定上下文是我们实际绑定到的数据对象。 In other words, it checks whether the data object pointed to by SelectedItem is actually the data object in the cell.换句话说,它检查SelectedItem指向的数据对象是否实际上是单元格中的数据对象。 If they are the same, we have the selected cell.如果它们相同,我们就有了选定的单元格。 We bind this into to the IsSelected property which can then be used in XAML or code behind to see if the view cell is in the selected state.我们将其绑定到IsSelected属性,然后可以在 XAML 或代码隐藏中使用该属性,以查看视图单元格是否处于选定状态。

There is just one caveat: if you want to set a default selected item when your page displays, you need to be a bit clever.只有一个警告:如果你想在页面显示时设置一个默认的选定项,你需要有点聪明。 Unfortunately, Xamarin Forms has no page Displayed event, we only have Appearing and this is too early for setting the default: the binding won't be executed then.不幸的是,Xamarin Forms 没有页面 Displayed 事件,我们只有 Appearing,这对于设置默认值还为时过早:绑定不会被执行。 So, use a little delay:所以,使用一点延迟:

protected override async void OnAppearing() {
  base.OnAppearing();

  Device.BeginInvokeOnMainThread(async () => {
    await Task.Delay(100);
    ListViewName.SelectedItem = ...;
  });
}

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

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