Xamarin.Forms ListView: establece el color de resaltado de un elemento seleccionado

¿Utilizando Xamarin.Forms , cómo puedo definir el color del resaltado / del fondo de un artículo selecto / tapped de ListView?

(Mi lista tiene un fondo negro y un color de texto blanco, por lo que el color de resaltado predeterminado en iOS es demasiado brillante.) En contraste, en Android no hay resaltado en absoluto, hasta una sutil línea gris horizontal.

Ejemplo: (izquierda: iOS, derecha: Android; mientras presiona "Barn2")

Parece que en realidad hay una forma multiplataforma para hacer esto que funciona tanto en iOS como en Android (no estoy seguro acerca de Windows). Utiliza sólo vinculante y no requiere procesadores personalizados (que parece raro). Este es un mash-up de un montón de google, por lo que gracias a cualquiera que me han prestado de …

Estoy asumiendo ViewCells, pero esto debe trabajar para las células del texto o de la imagen también. Sólo incluyo el código relevante aquí más allá del texto típico, la imagen, etc.

En su página haga algo como esto:

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

Su modelo personalizado podría ser algo como esto:

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

A continuación, para su ItemTemplate necesita una clase de celda personalizada algo como esto:

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

A continuación, en su controlador de eventos ItemSelected, haga lo siguiente. Tenga en cuenta que 'selected' es una instancia de MyModel utilizada para rastrear el elemento actualmente seleccionado. Estoy mostrando solamente color de fondo aquí, pero utilizo también esta técnica para invertir poner de relieve los colores del texto y del texto del detalle.

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

Tengo capturas de pantalla de iOS y Android si alguien quiere golpearme a 10 puntos para que pueda publicarlos 🙂

En Android simplemente edite su archivo Style.xml en Resources \ Value añadiendo esto:

 <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

Solución:

Dentro de un ViewCellRenderer personalizado puede establecer el SelectedBackgroundView . Simplemente crea un nuevo UIView con un color de fondo de tu elección y estás preparado.

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

Resultado:

Nota:

Con Xamarin.Forms parece ser importante crear un nuevo UIView lugar de simplemente establecer el color de fondo del actual.


Androide

Solución:

La solución que encontré en Android es un poco más complicada:

  1. Cree un nuevo ViewCellBackground.xml dentro de la carpeta 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> 

    Define formas sólidas con diferentes colores para el estado predeterminado y el estado "presionado" de un elemento de interfaz de usuario.

  2. Utilice una clase heredada para la View de su ViewCell , por ejemplo:

     public class TouchableStackLayout: StackLayout { } 
  3. Implementar un renderizador personalizado para esta clase que establece el recurso de fondo:

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

Resultado:

Tengo un proceso similar, completamente la plataforma de la cruz, sin embargo rastro el estado de la selección yo mismo y he hecho esto en 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> 

A continuación, en el evento 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; }; 

Como usted puede ver apenas fijé el ListView.SelectedItem a null para quitar cualesquiera de los estilos de la selección específicos de la plataforma que entran en juego.

En mi modelo tengo

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

Con el fin de establecer el color del elemento destacado que necesita para establecer el color de cell.SelectionStyle en iOS.

Este ejemplo es para establecer el color del elemento tocado en transparente.

Si lo desea, puede cambiarlo con otros colores de UITableViewCellSelectionStyle . Esto se escribirá en el proyecto de plataforma de iOS creando un nuevo renderizador de ListView personalizado en su proyecto Forms.

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

Para android puedes agregar este estilo en tus valores / 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> 

Tuve este mismo problema y lo resolví también mediante la creación de un procesador personalizado para iOS como Falko sugiere, sin embargo, evité la modificación de estilos para Android, me di cuenta de una manera de utilizar un procesador personalizado para Android también.

Es una especie de funky cómo la bandera seleccionada es siempre falsa para la célula de vista de Android es por eso que tuve que crear una nueva propiedad privada para rastrear. Pero aparte de eso creo que esto sigue un patrón más apropiado si desea utilizar renderizadores personalizados para ambas plataformas, en mi caso lo hice para TextCell pero creo que se aplica de la misma manera para otras CellViews.

Formularios Xamarin

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

Androide

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

Aquí está la plataforma puramente cruzada y la manera aseada:

1) Definir una acción desencadenante

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

2) Aplique la instancia de clase anterior como una acción de EventTrigger en XAML como se muestra a continuación

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

No olvide añadir xmlns:customTriggers="clr-namespace:CustomTriggers;assembly=ProjectAssembly"

Nota: Como ninguno de los elementos se encuentra en el modo seleccionado, el estilo de selección no se aplicará en ninguna de las plataformas.

  • La aplicación reanuda los resultados en bloqueo con FormsAppCompatActivity
  • Cómo generar un archivo .apk de Xamarin.Forms proyecto utilizando Visual Studio?
  • Consulta del cliente de Azure Mobile Service que no devuelve el control a Xamarin Form android client app
  • Xamarin.Forms popup "Nueva Versión Disponible"
  • Hacer desaparecer una barra de navegación en Xamarin.Forms
  • AlarmManager sólo funciona en un futuro próximo
  • Xamarin "intenta invocar el método virtual 'void android.view.View.unFocus (android.view.View)' en una referencia a un objeto nulo"
  • Cómo eliminar (Android) la barra de título de la aplicación en Xamarin.Forms?
  • Xamarin forma la posición de los elementos de la barra de herramientas para Android
  • Problemas de recursos de Android después de actualizar a Xamarin Forms 2.0
  • ¿Cómo mostrar el cuadro de alerta con Xamarin.Forms para su validación?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.