Xamarin.Forms iOS Dark Mode

Since the release of iOS 13 there has been a lot of information about the new features. In this case we are going to discuss The iOS Dark Mode and how we can implement it on our Xamarin.Forms applications.

I have come up with 3 simple steps to do this:

1.- Create/Separate your ResourceDictionaries files (If you don’t have Resources files I recommend you to use them! ) (Link) you will have one ResourceDictionary per mode (Light and Dark). And make sure you use DynamicResource instead of StaticResource so the styles automatically update when they are changed:

<?xml version="1.0" encoding="UTF-8"?>
<ResourceDictionary
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="darkside.Resources.DarkTheme">
    <Color x:Key="backgroundColor">#000000</Color>
    <Color x:Key="TextPrimaryColor">#FFFFFF</Color>
    <Color x:Key="TextSecondaryColor">#FFFFFF</Color>
    <Color x:Key="TextTernaryColor">#C8C8C8</Color>
    <Color x:Key="InvertedBackgroundColor">#000000</Color>
    <Color x:Key="InvertedTextColor">#000000</Color>
</ResourceDictionary>
<?xml version="1.0" encoding="UTF-8"?>
<ResourceDictionary
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="darkside.Resources.WhiteTheme">
    <Color x:Key="backgroundColor">#FFFFFF</Color>
    <Color x:Key="TextPrimaryColor">#000000</Color>
    <Color x:Key="TextSecondaryColor">#000000</Color>
    <Color x:Key="TextTernaryColor">#C8C8C8</Color>
    <Color x:Key="InvertedBackgroundColor">#000000</Color>
    <Color x:Key="InvertedTextColor">#FFFFFF</Color>
</ResourceDictionary>

2.- And most important… Create a ContentPage custom renderer, the important thing about the custom renderer is this method:

TraitCollectionDidChange(UITraitCollection previousTraitCollection)

which is telling us any time iOS notifies the app that traits have changed, the code checks that the change is different than the styles currently being displayed and it changes a global variable in our Xamarin.Forms.Application class which we are using to set the theme… So:

// This goes inside the App.xaml.cs
public static string AppTheme
{
    get; set;
}

And this is the Custom Renderer:

using System;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using YourNamespace.iOS.Renderers;
using YourNamespace.Resources;

[assembly: ExportRenderer(typeof(ContentPage), typeof(BaseContentPageRenderer))]
namespace YourNamespace.iOS.Renderers
{
    public class BaseContentPageRenderer : PageRenderer
    {
        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null || Element == null)
            {
                return;
            }

            try
            {
                SetAppTheme();
            }
            catch (Exception ex)
            {
            }
        }

        public override void TraitCollectionDidChange(UITraitCollection previousTraitCollection)
        {
            base.TraitCollectionDidChange(previousTraitCollection);
            Console.WriteLine($"TraitCollectionDidChange: {TraitCollection.UserInterfaceStyle} != {previousTraitCollection.UserInterfaceStyle}");

            if (TraitCollection.UserInterfaceStyle != previousTraitCollection.UserInterfaceStyle)
            {
                SetAppTheme();
            }
        }

        void SetAppTheme()
        {
            if (TraitCollection.UserInterfaceStyle == UIUserInterfaceStyle.Dark)
            {
                if (App.AppTheme == "dark")
                {
                    return;
                }
                Xamarin.Forms.Application.Current.Resources = new DarkTheme();
                App.AppTheme = "dark";
            }
            else
            {
                if (App.AppTheme != "dark")
                {
                    return;
                }
                Xamarin.Forms.Application.Current.Resources = new WhiteTheme();
                App.AppTheme = "light";
            }
        }
    }
}

3.- (Last and most tedious one) Edit your current styles to match the new look and feel on your application and make sure they look great!

This step took me quite some time but it was worth it 😀

One thing that I didn’t understand was:

  • If you change the mode while using the application not all of the Dynamic Resources are updated but if you close the app and open it again, you will be able to see the styles correctly. (So I will need to investigate further on that).

I was impressed by how easy it was to implement it the dark mode, the hard thing will be to refactor my old code to use separated ResourceDictionaries and change the color properties of each view to match the current theme… So are you ready to join the Dark side and impress your users???

Let me know your thoughts and comments on the section below or even better show off your application’s screenshots using the new iOS dark mode 😀

Related links:
https://devblogs.microsoft.com/xamarin/modernizing-ios-apps-dark-mode-xamarin/

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s