xamarin - Android 以编程方式更改主题

Dar*_* M. 2 xamarin.android xamarin xamarin.forms

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

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

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

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

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

我非常感谢您的帮助。

更新


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

我不确定,如果我可以订阅两个项目的事件。如果这是可能的,我该怎么做?

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

Fra*_*lue 7

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

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

public interface IThemeChanger
    {
        void ApplyTheme(string newTheme);
    }
Run Code Online (Sandbox Code Playgroud)

然后,在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);
            }
        }
Run Code Online (Sandbox Code Playgroud)

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

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));
    }
Run Code Online (Sandbox Code Playgroud)

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

    public readonly IThemeChanger ThemeChanger;
    public App(IThemeChanger themeChanger)
    {
        InitializeComponent();
        this.ThemeChanger = themeChanger;
        MainPage = new MainPage();
    }
Run Code Online (Sandbox Code Playgroud)

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

((App.Current) as App).ThemeChanger.ApplyTheme("Dark");
Run Code Online (Sandbox Code Playgroud)

如果你不直接实例化你的 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>());
        }
Run Code Online (Sandbox Code Playgroud)

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

在您的视图模型中:

public class LoginViewmModel{
    private readonly IThemeChanger themeChanger;

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

    private void ApplyTheme{
        themeChanger.ApplyTheme("Dark");
    }
}
Run Code Online (Sandbox Code Playgroud)