Forum Xamarin Xamarin.Forms

Force Change of android:textColor at runtime

I have the a TabbedPage Application and want to change the textcolor at runtime.

<Label Text="Color change works for this label, as i set textcolor" TextColor="{DynamicResource MyTextColor}"/>
<Label Text="but i want to have it work for all labels and other elements without DynamicResource=MyTextColor"/>

public partial class TabPage : ContentPage
protected override void OnAppearing()
{
    // this works
    Resources["MyTextColor"] = DarkTheme ? Color.Red : Color.Blue;

    // this does not work at runtime, textcolor defined in styles <item name="android:textColor">#43d5e6</item> does not update at runtime
    SetTheme(DarkTheme ? Resource.Style.MainTheme_Dark: Resource.Style.MainTheme_Light);
}

item name="android:textColor> is differently defined in MainTheme_Dark and MainTheme_Light and gets at once applied to new Pages (for example Navigation.PushModalAsync(new NavigationPage(new NewPage())), but it gets not applied to existing TabPage. I have to close my app and only afterwards, it correctly applies the new "item name=android:textColor> from the selected MainTheme.

How can I force to change android:textColor at runtime in the OnAppearing()-event?

Best Answer

  • AdamMeaneyAdamMeaney USMember ✭✭✭✭✭
    Accepted Answer

    I mean, you can avoid having to specify the dynamic resource on every page with implicit styles.

    That's what I have done to give my app the ability to be in dark mode even if the system is in light.

Answers

  • JarvanJarvan Member, Xamarin Team Xamurai

    Try to use DependencyService to call the SetTheme command. The DependencyService class is a service locator that enables Xamarin.Forms applications to invoke native platform functionality from shared code.

    The process for using the DependencyService:

    • Create an interface for the native platform functionality, in shared code.
    • Implement the interface in the required platform projects.
    • Register the platform implementations with the DependencyService.
    • Resolve the platform implementations from shared code, and invoke them.

    Tutorial:
    https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/introduction

  • frankmefrankme Member ✭✭

    Thank you for this suggestion. But does it really help? I can call SetTheme from MainActivity anywhere in my app (using this approach https://stackoverflow.com/a/52148130) and SetTheme then applies to all new elements (like popup, datepickers or newpages), but it does not apply to any already initialized elements.

    I looked at the official https://github.com/xamarin/xamarin-forms-samples/tree/master/UserInterface/ThemingDemo. Do I really have to use StyleTargetSetter and decorate all my ui-elements with Style="{StaticResource SmallLabelStyle}" to get this working?

    Is there no ReInitializeExistingPages() ? Or does DependencyService this magic, what the stackoverflow-solution does not do?

  • JarvanJarvan Member, Xamarin Team Xamurai

    Check this link about Check for Dark Mode in Xamarin.Forms.
    https://codetraveler.io/2019/09/11/check-for-dark-mode-in-xamarin-forms/

    Create a interface that will be used by the platform-specific libraries.

    namespace MyNamespace
    {
        public interface IEnvironment
        {
            Task<Theme> GetOperatingSystemTheme();
        }
    
        public enum Theme { Light, Dark }
    }
    

    App.cs

    using Xamarin.Forms;
    
    namespace MyNamespace
    {
        public App : Application
        {
            // ...
    
            protected override async void OnStart()
            {
                base.OnStart();
    
                Theme theme = await DependencyService.Get<IEnvironment>().GetOperatingSystemTheme();
    
                SetTheme(theme);
            }
    
            protected override async void OnResume()
            {
                base.OnResume();
    
                Theme theme = await DependencyService.Get<IEnvironment>().GetOperatingSystemTheme();
    
                SetTheme(theme);
            }
    
            void SetTheme(Theme theme)
            {
                //Handle Light Theme & Dark Theme
            }
    
        }
    }
    

    Get the Theme at platform project.

    public Task<Theme> GetOperatingSystemTheme()
    {
        if (Build.VERSION.SdkInt >= BuildVersionCodes.Froyo)
        {
            var uiModeFlags = CrossCurrentActivity.Current.AppContext.Resources.Configuration.UiMode & UiMode.NightMask;
    
            switch (uiModeFlags)
            {
                case UiMode.NightYes:
                    return Task.FromResult(Theme.Dark);
    
                case UiMode.NightNo:
                    return Task.FromResult(Theme.Light);
    
                default:
                    throw new NotSupportedException($"UiMode {uiModeFlags} not supported");
            }
        }
        else
        {
            return Task.FromResult(Theme.Light);
        }
    }
    

    Refer to:
    https://stackoverflow.com/questions/57879523/how-to-check-for-dark-mode-in-xamarin-forms

  • frankmefrankme Member ✭✭

    No, I already found this article, but this is something different. I don't want to check for Theme, I want to apply the Theme. When the users presses the SetTheme()-ActionButton, this changes only every future component, which is created afterwards. I doesn't change the current existing page. (It is similar to OneTimeBinding). I search for something like OnPropertyChanged for themes, that changes the theme of the current page or the tabbar.

  • AdamMeaneyAdamMeaney USMember ✭✭✭✭✭
    Accepted Answer

    I mean, you can avoid having to specify the dynamic resource on every page with implicit styles.

    That's what I have done to give my app the ability to be in dark mode even if the system is in light.

Sign In or Register to comment.