Xamarin.Forms change ListView SelectedItemColor

This project you can find at: https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor

We have to create a Custom Renderer for a ViewCell. So let’s create a class in the .NET Standard,/PCL Project:

https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor/tree/master/Xamarin.Forms.ChangeLvSelectedColor/Xamarin.Forms.ChangeLvSelectedColor/CustomControl/ListViewCustomViewCell.cs/

We created a property for the SelectedItem’s color. Don’t forget: this enum is a cutom enum, we have to create it:

https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor/blob/master/Xamarin.Forms.ChangeLvSelectedColor/Xamarin.Forms.ChangeLvSelectedColor/Helper/Enums.cs

Let’s create the platform specific code.

Android: we have to change the Android’s Theme at runtime via EventHandler.

We have to create a ViewCellRenderer class ( https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor/blob/master/Xamarin.Forms.ChangeLvSelectedColor/Xamarin.Forms.ChangeLvSelectedColor.Android/CustomRenderers/CustomViewCellRenderer.cs ):

using System.ComponentModel;
using Android.Content;
using Android.Views;
using Xamarin.Forms;
using Xamarin.Forms.ChangeLvSelectedColor.CustomControl.ListView;
using Xamarin.Forms.ChangeLvSelectedColor.Droid.CustomRenderers;
using Xamarin.Forms.ChangeLvSelectedColor.Helper;
using Xamarin.Forms.Platform.Android;
using static Xamarin.Forms.ChangeLvSelectedColor.Droid.MainActivity;

[assembly: ExportRenderer(typeof(CustomViewCell), typeof(CustomViewCellRenderer))]
namespace Xamarin.Forms.ChangeLvSelectedColor.Droid.CustomRenderers
{
    public class CustomViewCellRenderer : ViewCellRenderer
    {
        protected override global::Android.Views.View GetCellCore(Cell item, global::Android.Views.View convertView, ViewGroup parent, Context context)
        {
            var _cellCore = base.GetCellCore(item, convertView, parent, context);

            return _cellCore;
        }

        protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
        {
            base.OnCellPropertyChanged(sender, args);

            var extendedViewCell = (CustomViewCell)sender;

            if (extendedViewCell.SelectedCellColor == ListViewSelectedBackGroundColor.CianBlue)
            {
                AndroidEvents.OnAndroidThemeChangeNeeded_Event(null, Xamarin.Forms.ChangeLvSelectedColor.Droid.Resource.Style.MainCianBlueTheme);
            }
            else if (extendedViewCell.SelectedCellColor == ListViewSelectedBackGroundColor.Normal)
            {
                AndroidEvents.OnAndroidThemeChangeNeeded_Event(null, Xamarin.Forms.ChangeLvSelectedColor.Droid.Resource.Style.MainTheme);
            }
            else if (extendedViewCell.SelectedCellColor == ListViewSelectedBackGroundColor.Transparent)
            {
                AndroidEvents.OnAndroidThemeChangeNeeded_Event(null, Xamarin.Forms.ChangeLvSelectedColor.Droid.Resource.Style.MainTransparentTheme);
            }
        }
    }
}

AndroidEvents is a static class, and in this class we have to create an event ( https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor/blob/master/Xamarin.Forms.ChangeLvSelectedColor/Xamarin.Forms.ChangeLvSelectedColor.Android/MainActivity.cs ):

public class AndroidEvents
        {
            public static event EventHandler OnAndroidThemeChangeNeeded;

            public static void OnAndroidThemeChangeNeeded_Event(object sender, int id)
            {
                OnAndroidThemeChangeNeeded?.Invoke(sender, id);
            }
        }

This event invoke the Theme Changing at runtime. We have to call it, when the user interact with the ListView(ViewCell). We have to subscribe on this event in the MainActivity:

protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            AndroidEvents.OnAndroidThemeChangeNeeded += AndroidEvents_OnAndroidThemeChangeNeeded; ;
            LoadApplication(new App());
        }

        private void AndroidEvents_OnAndroidThemeChangeNeeded(object sender, int themeid)
        {
            RunOnUiThread(() => {
                SetTheme(themeid);
            });
        }

Finally, we have to create the Theme Shema in the style.xml (MainCianBlueTheme and MainTransparentTheme):

<?xml version="1.0" encoding="utf-8" ?>
<resources>

  <style name="MainTheme" parent="MainTheme.Base">
  </style>
  <style name="MainCianBlueTheme" parent="MainCianBlueTheme.Base">
  </style>
  <style name="MainTransparentTheme" parent="MainTransparentTheme.Base">
  </style>
  <!-- Base theme applied no matter what API -->
  <style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
    <!--If you are using revision 22.1 please use just windowNoTitle. Without android:-->
    <item name="windowNoTitle">true</item>
    <!--We will be using the toolbar so no need to show ActionBar-->
    <item name="windowActionBar">false</item>
    <!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette -->
    <!-- colorPrimary is used for the default action bar background -->
    <item name="colorPrimary">#2196F3</item>
    <!-- colorPrimaryDark is used for the status bar -->
    <item name="colorPrimaryDark">#1976D2</item>
    <!-- colorAccent is used as the default value for colorControlActivated
         which is used to tint widgets -->
    <item name="colorAccent">#FF4081</item>
    <!-- You can also set colorControlNormal, colorControlActivated
         colorControlHighlight and colorSwitchThumbNormal. -->
    <item name="windowActionModeOverlay">true</item>

    <item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
  </style>

  <style name="MainCianBlueTheme.Base" parent="MainTheme">
    <item name="android:colorPressedHighlight">@color/anlistviewSelection</item>
    <item name="android:colorLongPressedHighlight">@color/anlistviewSelection</item>
    <item name="android:colorFocusedHighlight">@color/anlistviewSelection</item>
    <item name="android:colorActivatedHighlight">@color/anlistviewSelection</item>
    <item name="android:activatedBackgroundIndicator">@color/anlistviewSelection</item>
  </style>

  <style name="MainTransparentTheme.Base" parent="MainTheme">
    <item name="android:colorPressedHighlight">@color/transparentlistviewSelection</item>
    <item name="android:colorLongPressedHighlight">@color/transparentlistviewSelection</item>
    <item name="android:colorFocusedHighlight">@color/transparentlistviewSelection</item>
    <item name="android:colorActivatedHighlight">@color/transparentlistviewSelection</item>
    <item name="android:activatedBackgroundIndicator">@color/transparentlistviewSelection</item>
  </style>

  <style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
    <item name="colorAccent">#FF4081</item>
  </style>
</resources>

and their @color variablesin the colors.xml (listviewSelection, anlistviewSelection, transparentlistviewSelection):

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <color name="launcher_background">#FFFFFF</color>
  <color name="colorPrimary">#3F51B5</color>
  <color name="colorPrimaryDark">#303F9F</color>
  <color name="colorAccent">#FF4081</color>
  <color name="listviewSelection">#f17a0a</color>
  <color name="anlistviewSelection">#40E0D0</color>
  <color name="transparentlistviewSelection">#00000000</color>
</resources>

iOS: we just have to create a platform specific version of the CustomViewCell class, and gain two properties a color (https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor/blob/master/Xamarin.Forms.ChangeLvSelectedColor/Xamarin.Forms.ChangeLvSelectedColor.iOS/CustomRenderer/CustomViewCellRenderer.cs):

using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.ChangeLvSelectedColor.CustomControl.ListView;
using Xamarin.Forms.ChangeLvSelectedColor.iOS.CustomRenderer;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(CustomViewCell), typeof(CustomViewCellRenderer))]
namespace Xamarin.Forms.ChangeLvSelectedColor.iOS.CustomRenderer
{
    public class CustomViewCellRenderer : ViewCellRenderer
    {
        public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
        {
            var customViewCell = (CustomViewCell)item;

            var cell = base.GetCell(item, reusableCell, tv);

            cell.SelectedBackgroundView = new UIView { BackgroundColor = GetColor(customViewCell.SelectedCellColor) };

            //You can define a new property in the CustomViewCell class, and you can use it here:
            //This code is set the unselected background color of the ViewCell:
            //cell.BackgroundColor = GetColor(customViewCell.UnSelectedCellColor);

            return cell;
        }

        public UIColor GetColor(Helper.ListViewSelectedBackGroundColor color)
        {
            switch (color)
            {
                case Helper.ListViewSelectedBackGroundColor.CianBlue:
                    return Color.FromHex("#40E0D0").ToUIColor();
                default:
                    return Color.Transparent.ToUIColor();
            }
        }
    }
}

Xamarin.Forms – ListView – CustomTextCell

This project, you can find at: https://github.com/officialdoniald/Xamarin.Forms.CustomControls

We have to create some platforms specific code (custom NavigationPage Renderer), because in the base Xamarin.Forms code, we can’t find this implementation. So first step, we have to create a class in the .NET Standard/PCL project: CustomTextCell ( https://github.com/officialdoniald/Xamarin.Forms.CustomControls/blob/master/XamarinForms.CustomControls/XamarinForms.CustomControls/ListView/CustomTextCell.cs ).

using Xamarin.Forms;
namespace XamarinForms.CustomControls.ListView
{
public class CustomTextCell : TextCell
{
public static readonly BindableProperty TextFontSizeProperty =
BindableProperty.Create(“TextFontSize”, typeof(double), typeof(CustomTextCell), default(double));
public static readonly BindableProperty DetailFontSizeProperty =
BindableProperty.Create(“DetailFontSize”, typeof(double), typeof(CustomTextCell), default(double));
public static readonly BindableProperty TextFontAttributesProperty =
BindableProperty.Create(“TextFontAttributes”, typeof(Enums.FontAttributes), typeof(CustomTextCell), default(Enums.FontAttributes));
public static readonly BindableProperty TextFontFamilyProperty =
BindableProperty.Create(“TextFontFamily”, typeof(string), typeof(CustomTextCell), default(string));
public static readonly BindableProperty DetailFontAttributesProperty =
BindableProperty.Create(“DetailFontAttributes”, typeof(Enums.FontAttributes), typeof(CustomTextCell), default(Enums.FontAttributes));
public static readonly BindableProperty DetailFontFamilyProperty =
BindableProperty.Create(“DetailFontFamily”, typeof(string), typeof(CustomTextCell), default(string));
/// <summary>
/// Set the Text font size.
/// </summary>
public double TextFontSize
{
get { return (double)GetValue(TextFontSizeProperty); }
set { SetValue(TextFontSizeProperty, value); }
}
/// <summary>
/// Set the Detail font size.
/// </summary>
public double DetailFontSize
{
get { return (double)GetValue(DetailFontSizeProperty); }
set { SetValue(DetailFontSizeProperty, value); }
}
/// <summary>
/// Set the Font Attributes of the Text.
/// </summary>
public Enums.FontAttributes TextFontAttributes
{
get { return (Enums.FontAttributes)GetValue(TextFontAttributesProperty); }
set { SetValue(TextFontAttributesProperty, value); }
}
/// <summary>
/// Set the Font Family of the Text.
/// </summary>
public string TextFontFamily
{
get { return (string)GetValue(TextFontFamilyProperty); }
set { SetValue(TextFontFamilyProperty, value); }
}
/// <summary>
/// Set the Font Attributes of the Detail.
/// </summary>
public Enums.FontAttributes DetailFontAttributes
{
get { return (Enums.FontAttributes)GetValue(DetailFontAttributesProperty); }
set { SetValue(DetailFontAttributesProperty, value); }
}
/// <summary>
/// Set the Font Family of the Detail.
/// </summary>
public string DetailFontFamily
{
get { return (string)GetValue(DetailFontFamilyProperty); }
set { SetValue(DetailFontFamilyProperty, value); }
}
}
}

Enums.FontAttributes is a custtom enum class, we can create it, but we can skip it too. You can find it at: https://github.com/officialdoniald/Xamarin.Forms.CustomControls/blob/master/XamarinForms.CustomControls/XamarinForms.CustomControls/Enums/HelperEnums.cs

Now we have to implement the platform spec. code at the various platforms.

Let’s begin with the Android site ( https://github.com/officialdoniald/Xamarin.Forms.CustomControls/blob/master/XamarinForms.CustomControls/XamarinForms.CustomControls.Android/CustomRenderer/CustomTextCellRenderer.cs ):

First, we have to implement the base class’s contructor:

public CustomTextCellRenderer() : base() { }
public CustomTextCellRenderer(System.IntPtr a, Android.Runtime.JniHandleOwnership b) : base() { }

Then we have to override the GetCellCore base function:

protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, ViewGroup parent, Android.Content.Context context)
{
var view = (CustomTextCell)item;
if (convertView == null)
{
convertView = new BaseCellView(context, item);
}
if (convertView is BaseCellView cellView)
{
cellView.SetImageVisible(false);
cellView.MainText = view.Text;
cellView.DetailText = view.Detail;
cellView.SetMainTextColor(view.TextColor);
cellView.SetDetailTextColor(view.DetailColor);
var control = ((LinearLayout)convertView);
if (control.GetChildAt(1) is LinearLayout linearLayout)
{
var mainTextView = (TextView)linearLayout.GetChildAt(0);
var detailTextView = (TextView)linearLayout.GetChildAt(1);
mainTextView.TextSize = (float)view.TextFontSize;
detailTextView.TextSize = (float)view.DetailFontSize;
var titleTypeface = Typeface.Create(view.TextFontFamily, ConvertFontAttributesToTypefaceStyle(view.TextFontAttributes));
var detailTypeface = Typeface.Create(view.DetailFontFamily, ConvertFontAttributesToTypefaceStyle(view.DetailFontAttributes));
mainTextView.Typeface = titleTypeface;
detailTextView.Typeface = detailTypeface;
}
}
return _cellCore = convertView;
}

If we implement the custom FontAttribute enum, we have to create the ConvertFontAttributesToTypefaceStyle() function:

private TypefaceStyle ConvertFontAttributesToTypefaceStyle(Enums.FontAttributes fontAttributes)
{
if (fontAttributes == Enums.FontAttributes.Bold)
{
return Android.Graphics.TypefaceStyle.Bold;
}
else if (fontAttributes == Enums.FontAttributes.BoldItalic)
{
return Android.Graphics.TypefaceStyle.BoldItalic;
}
else if (fontAttributes == Enums.FontAttributes.Italic)
{
return Android.Graphics.TypefaceStyle.Italic;
}
else return Android.Graphics.TypefaceStyle.Normal;
}

Let’s continue with the iOS site ( https://github.com/officialdoniald/Xamarin.Forms.CustomControls/blob/master/XamarinForms.CustomControls/XamarinForms.CustomControls.iOS/CustomRenderer/CustomTextCellRenderer.cs ):

The mechanism is the same, but we don’t need to implement the base class’s constructors, but we need to override the GetCell() function:

using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using XamarinForms.CustomControls.iOS.CustomRenderer;
using XamarinForms.CustomControls.ListView;
[assembly: ExportRenderer(typeof(CustomTextCell), typeof(CustomTextCellRenderer))]
namespace XamarinForms.CustomControls.iOS.CustomRenderer
{
public class CustomTextCellRenderer : TextCellRenderer
{
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
var view = (CustomTextCell)item;
var cell = base.GetCell(item, reusableCell, tv);
//cell.SelectedBackgroundView = new UIView { BackgroundColor = UIColor.Red };
var TextLabel = cell.TextLabel;
var DetailTextLabel = cell.DetailTextLabel;
TextLabel.Font = UIFont.FromName(view.TextFontFamily, (int)view.TextFontSize);
DetailTextLabel.Font = UIFont.FromName(view.DetailFontFamily, (int)view.DetailFontSize);
TextLabel.AttributedText = ConvertAttributes(TextLabel.Text, view.TextFontAttributes, (int)view.TextFontSize);
DetailTextLabel.AttributedText = ConvertAttributes(DetailTextLabel.Text, view.DetailFontAttributes, (int)view.DetailFontSize);
return cell;
}
private NSMutableAttributedString ConvertAttributes(string text, Enums.FontAttributes attr, int size)
{
if (attr == Enums.FontAttributes.Bold)
{
return new NSMutableAttributedString(
str: text,
font: UIFont.BoldSystemFontOfSize(size)
);
}
else if (attr == Enums.FontAttributes.Italic)
{
return new NSMutableAttributedString(
str: text,
font: UIFont.ItalicSystemFontOfSize(size)
);
}
//else if (attr == Enums.FontAttributes.BoldItalic)
//{
// var textattr = new NSMutableAttributedString(
// str: text,
// font: UIFont.BoldSystemFontOfSize(size)
// );
// textattr.Append(new NSMutableAttributedString(
// str: text,
// font: UIFont.ItalicSystemFontOfSize(size)
// ));
// return textattr;
//}
else
{
return new NSMutableAttributedString(
str: text,
font: UIFont.SystemFontOfSize(size)
);
}
}
}
}