Xamarin.Forms ListView: Set the highlight color of a tapped item
Solution 1
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.
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.
Android
Solution:
The solution I found on Android is a bit more complicated:
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); } }
Result:
Solution 2
In Android simply edit your styles.xml file under Resources\values adding this:
<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>
Solution 3
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...
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.
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:
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.
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 );
}
Solution 4
To change color of selected ViewCell
, there is a simple process without using custom renderer. Make Tapped
event of your ViewCell
as below
<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
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;
Solution 5
Only for Android
Add in your custom theme or your default theme under ProjectName.Android/Resources/values/styles.xml
<item name="android:colorActivatedHighlight">@android:color/transparent</item>
Related videos on Youtube
Comments
-
Falko about 2 years
Using Xamarin.Forms, how can I define the highlight/background color of a selected/tapped ListView item?
(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.)
Example: (left: iOS, right: Android; while pressing "Barn2")
-
Sten Petrov over 9 yearsIf setting the background color doesn't work for the existing UIView try calling the cell's SetNeedsLayout (or whatever that method was called) after setting its background color. UITableView tries to not perform layout whenever that's possible
-
Falko over 9 years@StenPetrov: Nope,
SetNeedsDisplay
or ``` SetNeedsLayout``` does not work. But it doesn't really matter, since assigningnew UIView {...}
is a pretty short workaround. -
Unsliced over 9 yearsThis works - at least a little bit. I'm finding that when an item is selected, this works, but when I then select another, the first goes back to the 'old' background - unless I scroll to hide it, then scroll again to reveal it, in which case the 'new' colour is used in the redraw.
-
SpaceMonkey about 9 yearsomg, thank you! I thought of that myself, but when I tried it didn't work. I'm not sure what I did wrong, but copying your code worked.
-
animekun about 9 yearsit is NOT working, you just draw hover the row, old color is still there, and you can still see 1 pixel row of that color at the bottom
-
Rohit Vipin Mathews almost 9 years@Greag.Deay -
ListView.SeparatorVisibility = SeparatorVisibility.None; ListView.SeparatorColor= Color.Transparent;
should solve the problem you mentioned. -
Falko about 8 yearsHow does that answer the question? You're not setting a color at all. Although the original highlight color on iOS is too bright, I didn't want to hide the highlighting completely.
-
Sawan Kumar Bundelkhandi about 8 years@Falko - Its setting the colour example, In the example shown I have set to transparent but you can set any colour of your choice.
-
Edgar about 8 yearsAnd how to change the font color?
-
Scuzzlebutt about 7 yearsThis method did work fine on my UWP project along with Android and iOS. Kick ass!
-
Ateik about 7 yearsthe issue is only happening on Android, so this is the best/cleanest solution for me
-
Scuzzlebutt about 7 yearsI had to use this iOS custom renderer in addition to Barry Sohl's solution to prevent my templated listview from changing the background color of all controls in the template to the binded background color. However, I did have to change
e.PropertyName == "ItemsSource"
toe.PropertyName == "SelectedItem"
to get it to work properly. -
wislon about 7 yearsThanks a bunch, this saved me hours! I can confirm it works for ViewCells (which is what I needed)
-
masterwok about 7 yearsOn Android the selected color isn't retained for me. I've tried using android:state_selected.. :[
-
Filipe Silva about 7 yearsDid anyone get this to work while setting a default value for the ListView's SelectedItem?
-
Marin Shalamanov almost 7 yearsEasiest solution for me too. It's such a pity Xamarin Forms don't have a customizable property for that.
-
mr5 almost 7 yearsWill this also for for contextual action menus? Such as long click on android and swipe left on iOS?
-
ToolmakerSteve over 6 yearsAs Falko mentioned, this doesn't give enough control over color on iOS.
UITableViewCellSelectionStyle
only mentions two built-in colors, blue and gray. -
ToolmakerSteve over 6 yearsHow does this help "set the highlight/background color of a tapped item"? Looks like what you've done is suppress any color change.
-
zafar over 6 yearsIt does not change the background color by any means. But helpful when user wants to suppress the item selection. This is usually helpful in the scenarios when user wants to launch the detail view when an item in the
ListView
is tapped but wants to suppress the selected item. -
Pxaml over 6 yearswill this solution work ,if the main project is on pcl ?
-
Falko over 6 yearsI think this does not answer the question, since you're not setting the color of the tapped item. You're just avoiding the selection altogether.
-
Marek about 6 yearsIf you are following MVVM pattern this is actually not a best approach.
Color
is not really related with the model itself - it's a strictly UI matter and framework dependent (Forms in this case). Setting i.e.IsSelected
flag in model with converter or style trigger in XAML would be more portable solution. -
wislon about 6 yearsthis works great for ListViews using the RetainElement caching strategy, but for those using the RecycleElement or RecycleElementAndDataTemplate strategy, the IsSelected property never changes - But we do get 'BindingContext' and 'Index' property changes. I'm still trying to figure out if I can use those somehow instead. So close! :)
-
Prince about 6 yearsI am unable to call list.First(...) .. It says IEnumerable does not contain a definition for First...
-
Adam about 6 years@Prince - you will need to add using System.Linq; at the top.
-
Adam about 6 yearsIf you have using System.Linq, then an IEnumerable certainly has the extension .First(). If you can't resolve this, ask another question on StackOverflow to debug that particular issue.
-
ToolmakerSteve about 6 yearsNot only does this not answer the question, this makes it impossible to select a row!
-
Paul Charlton about 6 yearsFair point, must have misread the question as I found my way here looking for a way to remove the selected row colour. I do still manage to select a row, through tap gestures if I remember correctly.
-
Tiago_nes almost 6 yearsdoes not work 100% because at the first selection i still see the default blue for half a second, but it is good enough.
-
Morse over 5 yearsSince the selected item gets changed it triggers
ItemSelected
event again, so in my case the further code ran into exception. -
user875234 over 5 yearsThat's a great solution. I'm not criticizing your solution. But that is too much code to add to change the color of a list item. If you have 10 little fixes like this your code just becomes a mess.
-
Denis Vitez over 5 yearsI created the Style.xml since there was none in my Android project, but this is not working for me. Do I need to add something else? Maybe a special theme? I'm using Xamarin.Forms.
-
Inrego about 5 yearsAnyone has an idea as to why the SelectedBackgroundColor is never set, when using it in an Implicit style?
-
Extragorey about 5 yearsHow do you tell
CustomTextCell
to useCustomTextCellRenderer
? Is there some attribute I'm missing? -
zafar over 4 yearsAlso this approach will not be able to address the color change for long press, in the scenarios where you have Context Actions defined on the ListView's ViewCell
-
thomasgalliker over 4 yearsTried it: Can no longer select a row when this effect is active. Rollback changes...
-
thomasgalliker over 4 yearsI would definitetly not handle the BackgroundColor in the viewmodel (MyModel in your case) as this is against the idea of MVVM. The viewmodel is here to prepare data which is then visualized by the view. If we start to mix these concepts,we will be soon back to Winforms times... happy coding then.
-
thomasgalliker over 4 years@Extragorey, you're probably missing the ExportRenderer call: [assembly: ExportRenderer(typeof(ExtendedViewCell), typeof(ExtendedViewCellRenderer))]
-
a.tarasevich over 4 yearsBest solution! Thanks!
-
Nk54 about 4 yearsI was using this technique but i have to say that like @FilipeSilva said, it doesn't work if the selected item is initialized in view model. Only work with user interaction. I've tried working around but didn't find a fix.
-
Vikas Lalwani about 4 yearsThis solution should have maximum votes and must be on top, as this is the easiest one.
-
Tornike Gomareli almost 4 yearsThe best solution, easiest and most beautiful. Should be on the top
-
Luis Lema almost 4 yearsIt works only when you select an item from the menu. It doesn' work the first time the menu is shown.
-
thomasgalliker almost 4 yearsNever use such code in production software. It may works on your machine, but whenever you use "some delay to wait a bit" this is an indicator for problems. What is 100ms is not enough on a very slow Nokia 3 Android phone?
-
thomasgalliker almost 4 yearsFurthermore, having a direct reference between the ListView's Name and the ItemTemplate means that you'll never be able to extract the DataTemplate to a separate file. If the DataTemplate grows large, you gonna end up with huge xaml files (as we did many times).
-
Gábor almost 4 yearsI've left Xamarin for Flutter more than a year ago and never looked back. Still, at the time this answer was written, this probably was the only way to accomplish it. If things have changed since and you know a better solution now, then you could edit, or better yet, provide a new answer.
-
tuke307 over 3 yearslook here for more information
-
cineam mispelt about 3 yearsSadly not working for me. The color in the question is when the item is "tapped", which i believe is different to after the tap when it then goes to "selected". This solution works for me on the selected item (after the tap) but "during" the tap i get the same faded pink as in the image in the question.
-
Softlion about 3 yearsSelectedBackgroundView is for selection, not highlightning. Question is about highlightning