> ## Content Index
> Fetch the complete content index at: https://codetraveler.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# Check for Dark Mode in Xamarin.Forms
- URL: https://codetraveler.io/2019/09/11/check-for-dark-mode-in-xamarin-forms/
- Published: 2019-09-11T19:22:00.000Z
- Updated: 2020-04-10T19:38:03.000Z
- Description: Both iOS 13 and Android Q now let the user enable Dark Mode for the operating system. Let's explore how to check whether the user has enabled Dark Mode in our Xamarin.Forms apps.
- Author: Brandon Minnick
- Tags: Xamarin.Forms, iOS, Android, Dark, Light, Dark Mode, Dark Theme, Xamarin, Xamarin.iOS, Xamarin.Android, Theme

**Update** (10 April 2020)**: C**ustom Renderers are no longer required to implement theming.[Xamarin.Forms has introduced the following APIs](https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Core/Application.cs?ref=codetraveler.io) in Xamarin.Forms Xamarin.Forms v4.6.0.616-pre4:

- `Xamarin.Forms.Application.Current.RequestedTheme`
- `Xamarin.Forms.Application.Current.RequestedThemeChanged`

You can find the completed solution that uses these updated APIs in this app:

- [https://github.com/brminnick/GitTrends](https://github.com/brminnick/GitTrends?ref=codetraveler.io)

---

Both [iOS 13](https://developer.apple.com/documentation/appkit/supporting%5Fdark%5Fmode%5Fin%5Fyour%5Finterface?ref=codetraveler.io) and [Android Q](https://developer.android.com/guide/topics/ui/look-and-feel/darktheme?ref=codetraveler.io) now let the user enable Dark Mode for the operating system. Let's explore how to check if the user has enabled Dark Mode in our Xamarin.Forms apps!

You can find the completed solution in the following apps:

- [https://github.com/brminnick/DarkModeSplashScreen](https://github.com/brminnick/DarkModeSplashScreen?ref=codetraveler.io)

## Xamarin.Forms

In our Xamarin.Forms project, let's create an interface called `IEnvironment` and an enum called `Theme` that will be used by the platform-specific libraries

```csharp
using System.Threading.Tasks;

namespace MyNamespace
{
    public interface IEnvironment
    {
        Theme GetOperatingSystemTheme();
        Task<Theme> GetOperatingSystemThemeAsync();
    }

    public enum Theme { Light, Dark }
}
```

After we've added the platform-specific code (in the Xamarin.iOS and Xamarin.Android sections below), we'll be able to detect the Theme from our Xamarin.Forms code. I recommend checking/setting the theme in `Application.OnStart` and `Application.OnResume` to ensure that our app always adhere's to the user's preference.

```csharp
using Xamarin.Forms;

namespace MyNamespace
{
    public App : Application
    {
        // ...
        
        protected override async void OnStart()
        {
            base.OnStart();

            Theme theme = DependencyService.Get<IEnvironment>().GetOperatingSystemTheme(); 
            
            SetTheme(theme);
        }
        
        protected override async void OnResume()
        {
            base.OnResume();
            
           	Theme theme = DependencyService.Get<IEnvironment>().GetOperatingSystemTheme(); 
            
            SetTheme(theme);            
        }
        
        void SetTheme(Theme theme)
        {
            //Handle Light Theme & Dark Theme
        }
    }    
}
```

## Xamarin.iOS

In our Xamarin.iOS project, we will retrieve the `TraitCollection.UserInterfaceStyle` value from the current `UIViewController` and check whether it is `UIUserInterfaceStyle.Light` or `UIUserInterfaceStyle.Dark`. 

These APIs were introduced in iOS 12.0, so we'll first check whether the device is running iOS 12 (or higher). If it is on a earlier version of iOS, we will return `Theme.Light`.

```csharp
using System;
using UIKit;
using Xamarin.Forms;
using MyNamespace;
using MyNamespace.iOS;

[assembly: Dependency(typeof(Environment_iOS))]
namespace MyNamespace.iOS
{
    public class Environment_iOS : IEnvironment
    { 
        public Theme GetOperatingSystemTheme()
        {
            //Ensure the current device is running 12.0 or higher, because `TraitCollection.UserInterfaceStyle` was introduced in iOS 12.0
            if (UIDevice.CurrentDevice.CheckSystemVersion(12, 0))
            {
                var currentUIViewController = GetVisibleViewController();
            
                var userInterfaceStyle = currentUIViewController.TraitCollection.UserInterfaceStyle;

                switch (userInterfaceStyle)
                {
                    case UIUserInterfaceStyle.Light:
                        return Theme.Light;
                    case UIUserInterfaceStyle.Dark:
                        return Theme.Dark;
                    default:
                        throw new NotSupportedException($"UIUserInterfaceStyle {userInterfaceStyle} not supported");
                }
            }
            else
            {
                return Theme.Light;
            }
        }
        
        // UIApplication.SharedApplication can only be referenced by the Main Thread, so we'll use Device.InvokeOnMainThreadAsync which was introduced in Xamarin.Forms v4.2.0
        public async Task<Theme> GetOperatingSystemThemeAsync() =>
        	Device.InvokeOnMainThreadAsync(GetOperatingSystemTheme);
        
		static UIViewController GetVisibleViewController()
        {
            UIViewController viewController = null;

            var window = UIApplication.SharedApplication.KeyWindow;

            if (window.WindowLevel == UIWindowLevel.Normal)
                viewController = window.RootViewController;

            if (viewController is null)
            {
                window = UIApplication.SharedApplication
                    .Windows
                    .OrderByDescending(w => w.WindowLevel)
                    .FirstOrDefault(w => w.RootViewController != null && w.WindowLevel == UIWindowLevel.Normal);                    

                viewController = window?.RootViewController ?? throw new InvalidOperationException("Could not find current view controller.");
            }

            while (viewController.PresentedViewController != null)
                viewController = viewController.PresentedViewController;

            return viewController;
        }
    }
}
```

## Xamarin.Android

In our Xamarin.Android project, we'll retrieve `Configuration.UiMode` from the current `Context` and check whether it is `UiMode.NightYes` or `UiMode.NightNo`.

**Note**: This code requires the [Plugin.CurrentActivity NuGet Package](https://www.nuget.org/packages/Plugin.CurrentActivity/?ref=codetraveler.io). Make sure to first add this NuGet package to your Xamarin.Android project. 

```csharp
using System;
using System.Threading.Tasks;
using Android.Content.Res;
using Plugin.CurrentActivity;
using Xamarin.Forms;

using MyNamespace;
using MyNamespace.Android;

[assembly: Dependency(typeof(Environment_Android))]
namespace MyNamespace.Android
{
    public class Environment_Android : IEnvironment
    {
	    public Task<Theme> GetOperatingSystemThemeAsync()  =>
        	Task.FromResult(GetOperatingSystemTheme());
            
        public Theme GetOperatingSystemTheme()
        {
            //Ensure the device is running Android Froyo or higher because UIMode was added in Android Froyo, API 8.0
            if(Build.VERSION.SdkInt >= BuildVersionCodes.Froyo)
            {
                var uiModeFlags = CrossCurrentActivity.Current.AppContext.Resources.Configuration.UiMode & UiMode.NightMask;
                
                switch(uiModelFlags)
                {
                    case UiMode.NightYes:
                        return Theme.Dark;
                    
                    case UiMode.NightNo:
                        return Theme.Light;
                        
                    default:
                        throw new NotSupportedException($"UiMode {uiModelFlags} not supported");
                }
            }
            else
            {
                return Theme.Light;
            }
        }
    }
}
```