Saturday 13 October 2018

How to change ListView SelectedItem Bg Color in Xamarin.Forms

Introduction

This article describes how we can change ListView SelectedItem bg color in Xamarin.Forms. Sometimes we may need to set different bg color for ListView selected item, So in this article, we can learn how to achieve this functionality using CustomRenderer.
Requirements:
  • This article source code is prepared by using Visual Studio 2017. And it is better to install latest visual studio updates from here.
  • This article is prepared on a MAC machine.
  • This sample project is Xamarin.Forms .Net standard project.
  • This sample app is targeted for Android, iOS. And tested for Android & iOS.
Description:

The creation of  Xamarin.Forms project is very simple in Visual Studio for Mac. It will creates three projects 
1) Shared Code
2) Xamarin.Android
3) Xamarin.iOS
Because Mac system with  Visual Studio for Mac it doesn't support Windows projects(UWP, Windows, Windows Phone)
The following steps will show you how to create Xamarin.Forms project in Mac system with  Visual Studio,
First, open the Visual Studio for Mac. And Click on New Project 

After that, we need to select whether you're doing Xamarin.Forms or Xamarin.Android or Xamarin.iOS project. if we want to create Xamarin.Forms project just follow the below screenshot.

Give the App Name i.e ListViewDemo.

Note: 
In the above screen under Shared Code, select use .NET Standard or Use Shared Library. Then click on Next Button and below screenshot will show you how to browse to save the project on our PC.

After click on Create, button it will create the ListViewDemo Xamarin.Forms project like below
  • ListViewDemo: It is for Shared Code
  • ListViewDemo.Droid: It is for Android.
  • ListViewDemo.iOS: It is for iOS

We need to follow below few steps to change selected-item background color for ListView.
.Net Standard/PCL: 

Step 1:
Create your own Xaml page name is ListViewPage.xaml, and make sure refer "CustomViewCell" class in Xaml by declaring a namespace for its location and using the namespace prefix on the control element. The following code example shows how the "CustomViewCell" renderer class can be consumed by a Xamlpage:
And here we are trying to set background color for ListView selected-item.
ListViewPage.xaml

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"  
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"  
  4.     xmlns:custom="clr-namespace:ListViewDemo.CustomControls;assembly=ListViewDemo"  
  5.     xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"  
  6.     BackgroundColor="White"  
  7.     x:Class="ListViewDemo.Views.ListViewPage">  
  8.     <ContentPage.Padding>  
  9.         <OnPlatform x:TypeArguments="Thickness"  
  10.             Android="0, 0, 0, 0"  
  11.             WinPhone="0, 0, 0, 0"  
  12.             iOS="0, 20, 0, 0"/>  
  13.     </ContentPage.Padding>  
  14.     <ContentPage.Content>  
  15.         <StackLayout Padding="30,40,30,0" Spacing="50" BackgroundColor="White" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">  
  16.             <Label Text="ListView SelectedItemColor"  HorizontalOptions="CenterAndExpand" FontSize="20" TextColor="Maroon" FontAttributes="Bold"/>  
  17.             <ListView Grid.Row="1" ItemsSource="{Binding OrdersList}" Footer="" ios:ListView.SeparatorStyle="FullWidth" HeightRequest="140" SeparatorColor="Gray">  
  18.                 <ListView.ItemTemplate>  
  19.                     <DataTemplate>  
  20.                         <custom:CustomViewCell SelectedItemBackgroundColor="#ADF3BE">  
  21.                             <ViewCell.View>  
  22.                                 <StackLayout Orientation="Horizontal" >  
  23.                                     <Label Text="{Binding OrderType}" VerticalOptions="CenterAndExpand" FontSize="Medium" Font="15" TextColor="Gray" HorizontalOptions="StartAndExpand"/>  
  24.                                     <StackLayout HorizontalOptions="EndAndExpand" Orientation="Horizontal" Spacing="15">  
  25.                                         <Frame OutlineColor="Green" HasShadow="false" Margin="0,8,0,8" BackgroundColor="Transparent" Padding="5">  
  26.                                             <Label Text="{Binding TotalCount}" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" FontSize="10" TextColor="Red"/>  
  27.                                         </Frame>  
  28.                                         <Image Source="back_icon.png" VerticalOptions="CenterAndExpand" HeightRequest="16" WidthRequest="16" HorizontalOptions="EndAndExpand"/>  
  29.                                     </StackLayout>  
  30.                                 </StackLayout>  
  31.                             </ViewCell.View>  
  32.                         </custom:CustomViewCell>  
  33.                     </DataTemplate>  
  34.                 </ListView.ItemTemplate>  
  35.             </ListView>  
  36.         </StackLayout>  
  37.     </ContentPage.Content>  
  38. </ContentPage>  
  
Note:
The "custom" namespace prefix can be named anything. However, the clr-namespace and assembly values must match the details of the custom renderer class. Once the namespace is declared the prefix is used to reference the custom control/layout.
Step 2:
Add some simple list data to bind ObservableCollection to the ListView in code behind. Also here I'm not following MVVM design pattern.
ListViewPage.xaml.cs
  1. using ListViewDemo.ViewModels;  
  2. using Xamarin.Forms;  
  3.   
  4. namespace ListViewDemo.Views  
  5. {  
  6.     public partial class ListViewPage : ContentPage  
  7.     {  
  8.         public ListViewPage()  
  9.         {  
  10.             InitializeComponent();  
  11.   
  12.             BindingContext = new ListViewPageViewModel();  
  13.         }  
  14.     }  
  15. }       

ViewModels:

ListViewPageviewModel.cs

  1. using System;    
  2. using System.Collections.Generic;    
  3. using System.Collections.ObjectModel;    
  4. using System.ComponentModel;    
  5. using System.Runtime.CompilerServices;    
  6. using ListViewDemo.Models;    
  7.     
  8. namespace ListViewDemo.ViewModels    
  9. {    
  10.     public class ListViewPageViewModel : INotifyPropertyChanged    
  11.     {    
  12.     
  13.         ObservableCollection<Order> _ordersList;    
  14.         public ObservableCollection<Order> OrdersList    
  15.         {    
  16.             get    
  17.             {    
  18.                 return _ordersList;    
  19.             }    
  20.             set    
  21.             {    
  22.                 _ordersList = value;    
  23.                 OnPropertyChanged("OrdersList");    
  24.             }    
  25.         }    
  26.     
  27.         protected bool SetProperty<T>(ref T backingStore, T value,    
  28.            [CallerMemberName]string propertyName = "",    
  29.            Action onChanged = null)    
  30.         {    
  31.             if (EqualityComparer<T>.Default.Equals(backingStore, value))    
  32.                 return false;    
  33.             backingStore = value;    
  34.             onChanged?.Invoke();    
  35.             OnPropertyChanged(propertyName);    
  36.             return true;    
  37.         }    
  38.     
  39.         //INotifyPropertyChanged implementation method    
  40.         public event PropertyChangedEventHandler PropertyChanged;    
  41.         protected void OnPropertyChanged([CallerMemberName] string propertyName = "")    
  42.         {    
  43.             var changed = PropertyChanged;    
  44.             if (changed == null)    
  45.                 return;    
  46.             changed.Invoke(thisnew PropertyChangedEventArgs(propertyName));    
  47.         }    
  48.     
  49.         public ListViewPageViewModel()    
  50.         {    
  51.             var ordersList = new ObservableCollection<Order>();    
  52.     
  53.             ordersList.Add(new Order() { OrderType = "Completed Orders", TotalCount = "56566" });    
  54.             ordersList.Add(new Order() { OrderType = "Limit Orders", TotalCount = "878" });    
  55.             ordersList.Add(new Order() { OrderType = "Market Orders", TotalCount = "39856" });    
  56.             ordersList.Add(new Order() { OrderType = "Stop Orders", TotalCount = "056708" });    
  57.             ordersList.Add(new Order() { OrderType = "Imbalance Orders", TotalCount = "64775674" });    
  58.             ordersList.Add(new Order() { OrderType = "Conditional Orders", TotalCount = "56" });    
  59.             ordersList.Add(new Order() { OrderType = "Scheduled Orders", TotalCount = "1457575763" });    
  60.             ordersList.Add(new Order() { OrderType = "Mid-Point Orders", TotalCount = "2443" });    
  61.             ordersList.Add(new Order() { OrderType = "Odd lot Orders", TotalCount = "65781" });    
  62.             ordersList.Add(new Order() { OrderType = "Pending Orders", TotalCount = "9896" });    
  63.     
  64.             OrdersList = ordersList;    
  65.         }    
  66.     }    
  67. }    

Step 3: 
In .Net Standard/PCL, create a class name is CustomViewCell which should inherit any ViewCell.
CustomViewCell.cs
  1. using Xamarin.Forms;      
  2.       
  3. namespace ListViewDemo.CustomControls      
  4. {      
  5.     public class CustomViewCell : ViewCell      
  6.     {      
  7.         public static readonly BindableProperty SelectedItemBackgroundColorProperty =      
  8.         BindableProperty.Create("SelectedItemBackgroundColor",      
  9.                                 typeof(Color),      
  10.                                 typeof(CustomViewCell),      
  11.                                 Color.Default);      
  12.       
  13.         public Color SelectedItemBackgroundColor      
  14.         {      
  15.             get { return (Color)GetValue(SelectedItemBackgroundColorProperty); }      
  16.             set { SetValue(SelectedItemBackgroundColorProperty, value); }      
  17.         }      
  18.     }      
  19. }     

Xamarin.Android:

In Android project, create a class name is CustomViewCellRenderer and make sure to add renderer registration for our CustomViewCell class on above of the namespace.

CustomViewCellRenderer.cs

  1. using System.ComponentModel;  
  2. using ListViewDemo.CustomControls;  
  3. using ListViewDemo.Droid.CustomControls;  
  4. using Android.Content;  
  5. using Android.Graphics.Drawables;  
  6. using Android.Views;  
  7. using Xamarin.Forms;  
  8. using Xamarin.Forms.Platform.Android;  
  9.   
  10. [assembly: ExportRenderer(typeof(CustomViewCell), typeof(CustomViewCellRenderer))]  
  11. namespace ListViewDemo.Droid.CustomControls  
  12. {  
  13.     public class CustomViewCellRenderer : ViewCellRenderer  
  14.     {  
  15.   
  16.         private Android.Views.View _cellCore;  
  17.         private Drawable _unselectedBackground;  
  18.         private bool _selected;  
  19.   
  20.         protected override Android.Views.View GetCellCore(Cell item,  
  21.                                                           Android.Views.View convertView,  
  22.                                                           ViewGroup parent,  
  23.                                                           Context context)  
  24.         {  
  25.             _cellCore = base.GetCellCore(item, convertView, parent, context);  
  26.   
  27.             _selected = false;  
  28.             _unselectedBackground = _cellCore.Background;  
  29.   
  30.             return _cellCore;  
  31.         }  
  32.   
  33.         protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)  
  34.         {  
  35.             base.OnCellPropertyChanged(sender, args);  
  36.   
  37.             if (args.PropertyName == "IsSelected")  
  38.             {  
  39.                 _selected = !_selected;  
  40.   
  41.                 if (_selected)  
  42.                 {  
  43.                     var extendedViewCell = sender as CustomViewCell;  
  44.                     _cellCore.SetBackgroundColor(extendedViewCell.SelectedItemBackgroundColor.ToAndroid());  
  45.                 }  
  46.                 else  
  47.                 {  
  48.                     _cellCore.SetBackground(_unselectedBackground);  
  49.                 }  
  50.             }  
  51.         }  
  52.     }  
  53. }  

Here OnCellPropertyChanged method instantiates background for ListView selected item. 
Xamarin.iOS:
In iOS project, create a class name is CustomViewCellRenderer and make sure to add renderer registration for our RoundedCornerView class in above of the namespace.
CustomViewCellRenderer.cs
  1. using ListViewDemo.CustomControls;  
  2. using UIKit;  
  3. using Xamarin.Forms;  
  4. using Xamarin.Forms.Platform.iOS;  
  5. using xamformsdemo.iOS.CustomControls;  
  6.   
  7. [assembly: ExportRenderer(typeof(CustomViewCell), typeof(CustomViewCellRenderer))]  
  8. namespace xamformsdemo.iOS.CustomControls  
  9. {  
  10.     public class CustomViewCellRenderer : ViewCellRenderer  
  11.     {  
  12.         public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)  
  13.         {  
  14.             var cell = base.GetCell(item, reusableCell, tv);  
  15.             var view = item as CustomViewCell;  
  16.             cell.SelectedBackgroundView = new UIView  
  17.             {  
  18.                 BackgroundColor = view.SelectedItemBackgroundColor.ToUIColor(),  
  19.             };  
  20.   
  21.             return cell;  
  22.         }  
  23.     }  
  24. }  
Here GetCell override method instantiates background for ListView selected item. 
Output:
 

Please download the source code from below.

No comments:

Post a Comment