xamarin - xamarin - Android 以编程方式更改主题
问题描述
我有一个多租户应用程序,并且必须在用户登录后切换主题。
到目前为止,当用户已经登录并启动应用程序时,我在 MainActivity OnCreate 方法上调用 setTheme() 。
这工作正常,应用程序显示在正确的主题中。
但是当用户未登录时,应用程序将以默认主题启动。登录后我可以识别用户并且必须更改主题。但是我该怎么做。登录过程不在android项目中,从那里我无法访问MainActivity。
如何设置新主题并重新创建应用程序?
我非常感谢您的帮助。
更新
登录方法目前在 MC.Core (Shared) (.NET Standard 2.0) 库中,而 MainActivity 在 MC.Android 库中。所以有一个插件,您可以访问项目的实际活动,但我不能使用它,因为它确实支持 .Net 标准。
如果我可以在两个项目上订阅一个事件,我也不放心。如果这是可能的,我该怎么做?
我最后的解决方案是将登录方法从我的核心项目移动到 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");
}
}
推荐阅读
- c# - 有没有办法我可以使用一种方法来添加
到字典? - terraform - 如果我尝试在 terraform 中循环事件,则会出错
- c# - 从 API 网关调用 C# lambda 的 JSON 序列化错误
- jsoup - 在 onButtonClick 之后使用 jsoup 发布表单
- ios - Q:如何重构尽可能多的带有属性的代码块的重复?
- javascript - React-Native 应用程序上的 AppLock 功能
- flutter - 使用 Dart 将字符串转换为列表/映射
- javascript - NodeJS (Express + PUG) MVC 端口检查器
- java - 创建一个编码字母
- r - R中的函数可以计算一个数字在向量中出现的次数