Xamarin.Forms ListView:设置点击项的突出显示颜色

Fal*_*lko 55 android listview ios xamarin xamarin.forms

使用Xamarin.Forms,如何定义所选/点击的ListView项目的高亮/背景颜色?

(我的列表有黑色背景和白色文字颜色,因此iOS上的默认高亮颜色太亮了.相比之下,在Android上根本没有突出显示 - 直到细微的水平灰线.)

示例:(左:iOS,右:Android;按"Barn2"时)

小智 83

在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>
Run Code Online (Sandbox Code Playgroud)

  • 这个问题仅发生在Android上,所以这对我来说是最好/最干净的解决方案 (4认同)
  • 对我来说也是最简单的解决方案。很遗憾 Xamarin Forms 没有可自定义的属性。 (2认同)
  • 我创建了 Style.xml,因为我的 Android 项目中没有 Style.xml,但这对我不起作用。我还需要添加其他东西吗?也许是一个特殊的主题?我正在使用 Xamarin.Forms。 (2认同)

小智 63

看起来实际上有一种跨平台的方式可以在iOS和Android上运行(不确定Windows).它仅使用绑定,不需要自定义渲染器(这似乎很少见).这是大量谷歌搜索的混搭,所以感谢任何我可能借来的人......

我假设ViewCells,但这也适用于Text或Image单元格.除了典型的文字,图片等,我只在此处提供相关代码.

在您的页面上执行以下操作:

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

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

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

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 ); 
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

        View = layout;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在ItemSelected事件处理程序中,执行以下操作.请注意,"已选择"是用于跟踪当前所选项目的MyModel实例.我这里只显示背景颜色,但我也使用此技术反向突出显示文本和细节文本颜色.

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 );
}
Run Code Online (Sandbox Code Playgroud)

我有来自iOS和Android的屏幕截图,如果有人想让我达到10分,那么我可以实际发布它们:)

  • 它不起作用,你只是画了一行,旧颜色仍然存在,你仍然可以在底部看到该颜色的1像素行 (5认同)
  • @Greag.Deay - `ListView.SeparatorVisibility = SeparatorVisibility.None; ListView.SeparatorColor = Color.Transparent;`应该解决你提到的问题. (4认同)
  • omg,谢谢!我自己想到了,但是当我尝试它时却没有用.我不确定我做错了什么,但复制你的代码是有效的. (2认同)

Fal*_*lko 27

iOS版

解:

在自定义内,ViewCellRenderer您可以设置SelectedBackgroundView.只需创建一个UIView具有您选择的背景颜色的新设置即可.

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

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

    return cell;
}
Run Code Online (Sandbox Code Playgroud)

结果:

注意:

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


Android的

解:

我在Android上找到的解决方案有点复杂:

  1. ViewCellBackground.xmlResources> drawable文件夹中创建一个新的drawable :

    <?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>
    
    Run Code Online (Sandbox Code Playgroud)

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

  2. 使用了一个继承类View你的ViewCell,例如:

    public class TouchableStackLayout: StackLayout
    {
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 为此类实现自定义渲染器设置后台资源:

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

结果:


Ada*_*ley 12

我有一个类似的过程,完全跨平台,但我自己跟踪选择状态,我在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>
Run Code Online (Sandbox Code Playgroud)

然后在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;

            };
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我只是将ListView.SelectedItem设置为null以删除任何特定于平台的选择样式.

在我的模型中,我有

        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
            }
        }
Run Code Online (Sandbox Code Playgroud)


小智 10

我有同样的问题,我通过为iOS创建自定义渲染器来解决它,正如Falko建议的那样,但是,我避免了Android的样式修改,我想出了一种方法来为Android使用自定义渲染器.

对于android视图单元格来说,所选标志总是假的,这是一种时髦的方式,这就是为什么我必须创建一个新的私有属性来跟踪它.但除此之外,如果您想为两个平台使用自定义渲染器,我认为这遵循更合适的模式.在我的情况下,我为TextCell做了它,但我相信它对其他CellView应用相同的方式.

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); }
        }
    }
Run Code Online (Sandbox Code Playgroud)

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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 有没有人在为 ListView 的 SelectedItem 设置默认值时让它起作用? (2认同)

Arv*_*iya 7

要更改selected的颜色ViewCell,有一个简单的过程无需使用自定义渲染器。使Tapped您的事件ViewCell如下

<ListView.ItemTemplate>
    <DataTemplate>
        <ViewCell Tapped="ViewCell_Tapped">            
        <Label Text="{Binding StudentName}" TextColor="Black" />
        </ViewCell>
    </DataTemplate>
</ListView.ItemTemplate>
Run Code Online (Sandbox Code Playgroud)

在您的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;
    }
} 
Run Code Online (Sandbox Code Playgroud)

像这样lastCell在您的顶部声明ContentPageViewCell lastCell;

  • 该解决方案应该获得最高票数并且必须位于顶部,因为这是最简单的解决方案。 (4认同)
  • 仅当您从菜单中选择一个项目时它才起作用。第一次显示菜单时它不起作用。 (3认同)
  • 最好的解决方案,最简单,最漂亮。应该在顶部 (2认同)

zaf*_*far 6

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

1)定义触发动作

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

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

 <ListView x:Name="YourListView" ItemsSource="{Binding ViewModelItems}">
    <ListView.Triggers>
        <EventTrigger Event="ItemSelected">
            <customTriggers:DeselectListViewItemAction></customTriggers:DeselectListViewItemAction>
        </EventTrigger>
    </ListView.Triggers>
</ListView>
Run Code Online (Sandbox Code Playgroud)

别忘了添加 xmlns:customTriggers="clr-namespace:CustomTriggers;assembly=ProjectAssembly"

注意:由于您的所有项目均未处于选定模式,因此不会在任一平台上应用选择样式.


Jee*_*aJP 6

仅适用于Android

添加您的自定义主题

<item name="android:colorActivatedHighlight">@android:color/transparent</item>
Run Code Online (Sandbox Code Playgroud)