Alan2
Alan2

Reputation: 24572

How can programmatically change from Light Mode to Dark Mode in Xamarin.Forms Android and / or programmatically change the color of the scroll bar?

I want to allow my user to select the AppTheme as he wants. Following are the options I want to give :-

  1. Automatic (As per the user selection in Settings).
  2. Light Mode
  3. Dark Mode

I found a solution to use the below code:-

        if(theme == App.Theme.Light)
        {
            Delegate.SetLocalNightMode(AppCompatDelegate.ModeNightNo);
        } else
        {
            Delegate.SetLocalNightMode(AppCompatDelegate.ModeNightYes);
        }

But this code recreates the entire activity and on the click on the button, I am again taken to the LoginPage of my App.

Can anyone suggest me a way to programmatically change from Light Mode to Dark Mode in Xamarin.Forms Android?

Also does anyone know another way that I could programmatically change the color of the scroll bar.

Upvotes: 1

Views: 2773

Answers (2)

Morse
Morse

Reputation: 9124

Have two style files Light and Dark XAML and ThemeHelper class which switches the themes at run time

Refer this https://github.com/jamesmontemagno/Hanselman.Forms/tree/vnext/src/Hanselman/Styles

Update

As mentioned this sample project has great resources for theme switching.

Light Theme

<?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="TestApp.LightTheme">
    <Color
        x:Key="TextColor">#ababab</Color>
    <Color
        x:Key="GenericBackground">#e3e3e3</Color>
    <Color
        x:Key="AppBackground">#FFFFFF</Color>
</ResourceDictionary>

Dark theme

<?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="TestApp.DarkTheme">
    <Color
        x:Key="TextColor">#e3e3e3</Color>
    <Color
        x:Key="GenericBackground">#ababab</Color>
    <Color
        x:Key="AppBackground">#000000</Color>
</ResourceDictionary>

ThemeHelper

public class ThemeHelper
{

    public static Theme CurrentTheme = Theme.Light;

    public static void ChangeTheme(Theme theme, bool forceTheme = false)
    {
        // don't change to the same theme
        if (theme == CurrentTheme && !forceTheme)
            return;

        //// clear all the resources
        var applicationResourceDictionary = Application.Current.Resources;
        ResourceDictionary newTheme;
        if (theme == Theme.Default)
        {

            theme = AppInfo.RequestedTheme == AppTheme.Dark ? Theme.Dark : Theme.Light;
        }

        switch (theme)
        {
            case Theme.Light:
                newTheme = new LightTheme();
                break;
            case Theme.Dark:
                newTheme = new DarkTheme();
                break;
            case Theme.Default:
            default:
                newTheme = new LightTheme();
                break;
        }

        ManuallyCopyThemes(newTheme, applicationResourceDictionary);

        CurrentTheme = theme;

        var background = (Color)App.Current.Resources["AppBackground"];

    }

    static void ManuallyCopyThemes(ResourceDictionary fromResource, ResourceDictionary toResource)
    {
        foreach (var item in fromResource.Keys)
        {
            toResource[item] = fromResource[item];
        }
    }
}

Theme enum

public enum Theme
{
    Default,
    Light,
    Dark
}

Before starting the app initialize theme , you can retrieve it from Application settings or from DB like SQLite or API too

public App()
{
    InitializeComponent();
    ThemeHelper.ChangeTheme(Theme.Default);
    MainPage = new NavigationPage(new MainPage());
}

Make sure you use DynamicResource in this approach

<?xml version="1.0" encoding="utf-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:d="http://xamarin.com/schemas/2014/forms/design"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    BackgroundColor="{DynamicResource AppBackground}"
    x:Class="TestApp.MainPage">
    <ContentPage.ToolbarItems>
        <ToolbarItem
            Text="Default"
            Clicked="ToolbarItem_Clicked" />
        <ToolbarItem
            Text="Light"
            Clicked="ToolbarItem_Clicked_1" />
        <ToolbarItem
            Text="Dark"
            Clicked="ToolbarItem_Clicked_2" />
    </ContentPage.ToolbarItems>
    <StackLayout>
        <Label
            Text="Welcome to Xamarin.Forms!"
            HorizontalOptions="Center"
            VerticalOptions="CenterAndExpand"
            TextColor="{DynamicResource TextColor}"
            BackgroundColor="{DynamicResource GenericBackground}" />
        <Label
            x:Name="label"
            TextColor="{DynamicResource TextColor}"
            BackgroundColor="{DynamicResource GenericBackground}"
            HorizontalOptions="Center"
            VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

Screenshot

You may still need some changes in Android with respect to different API levels.

Other reference

Theming Dark mode detection

Android Dark Theme

Upvotes: 4

Tuğ&#231;e Arar
Tuğ&#231;e Arar

Reputation: 806

You can use DynamicResources for implement dynamic theme functionality without redirection. You can follow these documents.

Upvotes: 0

Related Questions