Android Xamarin.Forms ListView:设置点击项目的高亮颜色
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25885238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Xamarin.Forms ListView: Set the highlight color of a tapped item
提问by Falko
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”)
采纳答案by Falko
iOS
IOS
Solution:
解决方案:
Within a custom ViewCellRenderer
you can set the SelectedBackgroundView
. Simply create a new UIView
with a background color of your choice and you're set.
在自定义中,ViewCellRenderer
您可以设置SelectedBackgroundView
. 只需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 newUIView
rather than just setting the background color of the current one.
使用 Xamarin.Forms 创建一个新的UIView
而不是仅仅设置当前的背景颜色似乎很重要。
Android
安卓
Solution:
解决方案:
The solution I found on Android is a bit more complicated:
我在 Android 上找到的解决方案有点复杂:
Create a new drawable
ViewCellBackground.xml
within theResources
>drawable
folder:<?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.
Use a inherited class for the
View
of yourViewCell
, e.g.:public class TouchableStackLayout: StackLayout { }
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); } }
ViewCellBackground.xml
在Resources
>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>
它为 UI 元素的默认状态和“按下”状态定义了具有不同颜色的实心形状。
View
为您的使用继承的类ViewCell
,例如:public class TouchableStackLayout: StackLayout { }
为此类设置背景资源实现自定义渲染器:
public class ElementRenderer: VisualElementRenderer<Xamarin.Forms.View> { protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e) { SetBackgroundResource(Resource.Drawable.ViewCellBackground); base.OnElementChanged(e); } }
Result:
结果:
回答by mfranc28
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>
回答by Barry Sohl
It looks like there is actually a cross-platform way to do this that works on both iOS and Android (not sure about 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...
看起来实际上有一种跨平台的方式可以在iOS和Android上运行(不确定Windows)。它只使用绑定,不需要自定义渲染器(这似乎很少见)。这是大量谷歌搜索的混搭,所以感谢任何我可能借用的人......
I am assuming ViewCells, but this should work for Text or Image cells as well. I am only including the relevant code here beyond the typical text, image, etc.
我假设使用 ViewCells,但这也适用于文本或图像单元格。除了典型的文本、图像等,我只在此处包含相关代码。
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. Note that 'selected' is an instance of MyModel used to track the currently selected item. I am only showing background color here, but I also use this technique to reverse highlight the text and detail text colors.
然后在您的 ItemSelected 事件处理程序中,执行以下操作。请注意,'selected' 是用于跟踪当前所选项目的 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 );
}
回答by Arvind Chourasiya
To change color of selected ViewCell
, there is a simple process without using custom renderer. Make Tapped
event of your ViewCell
as below
要更改 selected 的颜色ViewCell
,有一个简单的过程,无需使用自定义渲染器。使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;
像这样lastCell
在你的顶部声明ContentPage
ViewCell lastCell;
回答by Adam Pedley
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
{
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
}
}
回答by alexcons
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. 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.
对于 android 视图单元格,所选标志始终为 false 的方式有点奇怪,这就是为什么我必须创建一个新的私有属性来跟踪它。但除此之外,如果您想为两个平台使用自定义渲染器,我认为这遵循更合适的模式,在我的情况下,我为 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 中实际使用新的自定义控件。
回答by JeePakaJP
Only for Android
仅适用于安卓
Add in your custom theme
添加您的自定义主题
<item name="android:colorActivatedHighlight">@android:color/transparent</item>
回答by zafar
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.
注意:由于您的所有项目均未处于选定模式,因此选择样式将不会应用于任一平台。
回答by Luigino De Togni
I have & use a solution similar to @adam-pedley. No custom renderers, in xaml i bind background ViewCell Property
我有并使用了类似于@adam-pedley 的解决方案。没有自定义渲染器,在 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). I hope this solution will be usefull for somebody
我的示例是通过 Xamarin Forms Maps(相同内容页面)中的地点列表视图提取的。我希望这个解决方案对某人有用
回答by Damien Doumer
The easiest way to accomplish this on android is by adding the following code to your custom style :
在 android 上完成此操作的最简单方法是将以下代码添加到您的自定义样式:
@android:color/transparent
@android:颜色/透明