

<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和Android上实现这个,不确定是否适用于Windows(可能性较小)。它只使用绑定并且不需要自定义渲染器(这似乎很罕见)。这是许多谷歌搜索的混合物,因此感谢任何我可能借鉴的人……
我假设使用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实例。我这里仅显示背景颜色,但我也使用此技术来反转突出显示文本和详细文本颜色。
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 );
}
ListView.SeparatorVisibility = SeparatorVisibility.None;
和 ListView.SeparatorColor= Color.Transparent;
这两行代码可以解决你提到的问题。 - Rohit Vipin MathewsColor
实际上与模型本身没有真正的关系 - 它是一个严格的UI问题,并且依赖于框架(在此情况下为Forms)。在XAML中使用转换器或样式触发器来设置模型中的 IsSelected
标志会更具可移植性的解决方案。 - Marek解决方案:
在自定义的 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;
}
结果:
注意:
使用 Xamarin.Forms 时,创建一个新的UIView
比仅设置当前视图的背景颜色更为重要。
解决方案:
我在Android上发现的解决方案有点复杂:
在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>
它定义了UI元素的默认状态和“按下”状态的不同颜色的实心形状。
为您的的
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);
}
}
结果:
SetNeedsDisplay
或SetNeedsLayout
不起作用。但这并不重要,因为分配new UIView {...}
是一个相当简短的解决方法。 - Falko要更改所选 ViewCell
的颜色,有一个简单的过程可以不使用自定义渲染器。将您的 ViewCell
的 Tapped
事件设置如下:
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Tapped="ViewCell_Tapped">
<Label Text="{Binding StudentName}" TextColor="Black" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
在你的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;
}
}
在你的ContentPage
顶部这样声明lastCell
:ViewCell lastCell;
仅适用于Android
将其添加到您的自定义主题或默认主题中,在ProjectName.Android/Resources/values/styles.xml下。
<item name="android:colorActivatedHighlight">@android:color/transparent</item>
我有一个类似的流程,完全跨平台,但我自己跟踪选择状态,并且我是在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,以删除任何涉及特定平台选择样式的影响。
在我的模型中,我有
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;
}
bool IsSelected
属性。然后在视图中,使用 IValueConverter
在 ItemTemplate 中将 isSelected
映射到所需的颜色。 - ToolmakerSteve我遇到了同样的问题,像Falko建议的那样为iOS创建了自定义渲染器来解决它,但是我避免了修改Android的样式,我想出了一种方法也为Android创建了自定义渲染器。
Android视图单元格中选择标志始终为false,这有点奇怪,所以我不得不创建一个新的私有属性来跟踪它。但除此之外,如果你想为两个平台使用自定义渲染器,我认为这遵循了一种更合适的模式,在我的情况下,我是针对TextCell做的,但我相信其他CellViews也可以同样适用。
Xamarin Forms
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
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);
}
}
}
}
然后,在.xaml页面中,您需要添加一个XMLNS引用,指回新的CustomViewCell...
xmlns:customuicontrols="clr-namespace:MyMobileApp.CustomUIControls"
别忘了在你的XAML中实际使用新的自定义控件。
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"
注意:由于您的项目没有处于选中模式,所以选择样式将不会应用于任何平台。
ListView
中点击一个项目并启动详细视图,但又想抑制所选项目时,这是有帮助的。 - zafar我使用类似于@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>
在代码(MVVM)中,我通过boolToColor转换器保存lastitemselected,并更新背景颜色。
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)));
}
}
我的例子是通过Xamarin Forms地图上的列表视图提取的位置。我希望这个解决方案对某些人有用。
我发现这个很棒的选项,使用效果请点击这里。
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()
{
}
}
}
安卓:
[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()
{
}
}
}
表单:
ListView_Demo.Effects.Add(Effect.Resolve($"MyEffects.ListViewHighlightEffect"));