首页 > 解决方案 > xamarin - Android 以编程方式更改主题

问题描述

我有一个多租户应用程序,并且必须在用户登录后切换主题。

到目前为止,当用户已经登录并启动应用程序时,我在 MainActivity OnCreate 方法上调用 setTheme() 。

这工作正常,应用程序显示在正确的主题中。

但是当用户未登录时,应用程序将以默认主题启动。登录后我可以识别用户并且必须更改主题。但是我该怎么做。登录过程不在android项目中,从那里我无法访问MainActivity。

如何设置新主题并重新创建应用程序?

我非常感谢您的帮助。

更新


登录方法目前在 MC.Core (Shared) (.NET Standard 2.0) 库中,而 MainActivity 在 MC.Android 库中。所以有一个插件,您可以访问项目的实际活动,但我不能使用它,因为它确实支持 .Net 标准。

如果我可以在两个项目上订阅一个事件,我也不放心。如果这是可能的,我该怎么做?

我最后的解决方案是将登录方法从我的核心项目移动到 Android 项目。但在这种情况下,我必须为每个平台实现这个。

标签: xamarinxamarin.formsxamarin.android

解决方案


要从网络标准项目调用 MainActivity 中的方法,您需要将对 MainActivity 的引用传递给标准项目。最好的方法是传递对共享网络标准项目 App 构造函数的引用,该构造函数是从 MainActivity 调用的。当然,您不能在您的 App 构造函数中声明 MainActivity 类型的参数,因为您的网络标准项目无法引用 Android 项目,并且因为,如果您将来要实现您的应用程序的 iOS 和/或 UWP 版本,您需要一个所有这些不同项目之间的通用类型。

所以,你必须在你的网络标准项目中定义一个接口:

public interface IThemeChanger
    {
        void ApplyTheme(string newTheme);
    }

然后,在Android项目中,让你的MainActivity实现这个接口:

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IThemeChanger
    {
        public void ApplyTheme(string newTheme)
        {
            if (newTheme?.ToLower() == "dark")
            {
                SetTheme(Resource.Style.Base_Theme_AppCompat);
            }
            else
            {
                SetTheme(Resource.Style.Base_Theme_AppCompat_Light);
            }
        }

并使其在应用程序类的构造函数中传递对自身的引用:

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

        base.OnCreate(savedInstanceState);
        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
        LoadApplication(new App(this));
    }

然后,在网络标准 App 类中,更改构造函数,使其接受 IThemeChanger 类型的参数,并将对它的引用存储在私有或公共字段中(取决于您是否需要从 App 类外部访问它):

    public readonly IThemeChanger ThemeChanger;
    public App(IThemeChanger themeChanger)
    {
        InitializeComponent();
        this.ThemeChanger = themeChanger;
        MainPage = new MainPage();
    }

然后,在您的登录页面中,用户登录成功后,相应地更改主题,例如:

((App.Current) as App).ThemeChanger.ApplyTheme("Dark");

如果您不直接实例化 App 类而是使用依赖注入容器,则将 MainActivity 的当前实例注册为容器的 IThemeChanger 接口的实现者,并在 ViewModel 的构造函数中简单地请求 IThemeChanger 实例。当然,语法会根据您使用的 DI 容器而有所不同,这里是 Caliburn.Micro SimpleContainer 的示例:

    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IThemeChanger
{
        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);

            var container = IoC.Get<SimpleContainer>();
            if (container.HasHandler<IThemeChanger>())
            {
                container.UnregisterHandler<IThemeChanger>();
            }
            container.Instance<IThemeChanger>(this);

            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            LoadApplication(container.GetInstance<App>());
        }

在这种情况下,请注意,在应用恢复期间可以创建一个新的 MainActivity 实例,因此您需要检查该接口是否可能先前注册并取消注册。

在您的视图模型中:

public class LoginViewmModel{
    private readonly IThemeChanger themeChanger;

    public LoginViewModel(IThemeChanger themeChanger){
        this.themeChanger = themChanger;
    }

    private void ApplyTheme{
        themeChanger.ApplyTheme("Dark");
    }
}

推荐阅读