动态更改 android 的强调色
Dynamically change android's accent color
我将 Android 的强调色设置为灰色,因此它在任何主题(浅色或深色)中看起来都很正常。例如,灰色非常适合编辑控件,但事实证明它也用于警告取消按钮的文本。所以现在它在浅色主题中看起来很好,但在深色主题中非常糟糕。
如何从 Xamarin.Forms 应用动态更改 Android 的 colorAccent
?
编辑:这是 my theme changing code 目前的情况。 (我没有使用 AppThemeBinding
因为这种方法允许两个以上的主题)
你不能,因为强调色是在主题中定义的,而主题是 read-only。我假设动态意味着以编程方式。
在Xamarin Forms中,我们可以使用DependencyService to call native method. Fortunately, Android document provide the method setLocalNightMode来修改本地的DarkMode。需要注意的是,此方法不能修改手机设置的配置。
现在我们可以创建一个IDarkModeService
接口:
public interface IDarkModeService
{
void SetDarkMode(bool value);
}
然后在Android解决方案中实现它的方法:
public class DarkModeService : IDarkModeService
{
public void SetDarkMode(bool value)
{
if (value)
{
MainActivity.instance.Delegate.SetLocalNightMode(AppCompatDelegate.ModeNightYes);
MainActivity.instance.Recreate();
}
else
{
MainActivity.instance.Delegate.SetLocalNightMode(AppCompatDelegate.ModeNightNo);
MainActivity.instance.Recreate();
}
}
}
这里我们需要从MainActivity
创建一个静态的instance
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity instance { set; get; }
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
instance = this;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
}
}
并且不要忘记在 styles.xml
中添加配置以使应用程序支持 DarkMode:
<style name="MainTheme" parent="Theme.AppCompat.DayNight.NoActionBar"></style>
最后,我们可以调用Xamarin Forms中的依赖方法如下:
private async void ShowDialog_Clicked(object sender, EventArgs e)
{
await DisplayAlert("Alert", "You have been alerted", "OK");
}
private void SetDarkMode_Clicked(object sender, EventArgs e)
{
DependencyService.Get<IDarkModeService>().SetDarkMode(true);
}
private void CancelDarkMode_Clicked(object sender, EventArgs e)
{
DependencyService.Get<IDarkModeService>().SetDarkMode(false);
}
效果:
==================================更新======== ========================
如果需要自定义每个 Theme 的样式,可以在运行时交换 Theme。
首先,您可以在 Xamrin Forms 中存储一个主题标志(DarkMode):
private void SetDarkMode_Clicked(object sender, EventArgs e)
{
Preferences.Set("DarkMode", true);
DependencyService.Get<IDarkModeService>().SetDarkMode(true);
}
private void CancelDarkMode_Clicked(object sender, EventArgs e)
{
Preferences.Set("DarkMode", false);
DependencyService.Get<IDarkModeService>().SetDarkMode(false);
}
然后在里面添加每个Theme样式styles.xml:
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<style name="MainTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
</style>
<style name="DayTheme" parent="MainTheme">
</style>
<style name="NightTheme" parent="MainTheme" >
<item name="buttonBarPositiveButtonStyle">@style/positiveBtnStyle</item>
<item name="buttonBarNegativeButtonStyle">@style/negativeBtnstyle</item>
</style>
<!--style of sure button-->
<style name="positiveBtnStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
<item name="android:textColor">#0000ff</item>
</style>
<!--style of cancel button-->
<style name="negativeBtnstyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
<item name="android:textColor">#999999</item>
</style>
</resources>
最后,在MainActivity.cs中创建视图之前更改主题:
public static MainActivity instance { set; get; }
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
instance = this;
var darkMode = Preferences.Get("DarkMode", false);
if (darkMode)
{
this.SetTheme(Resource.Style.NightTheme);
}
else
{
this.SetTheme(Resource.Style.DayTheme);
}
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
现在我们可以看到按钮的颜色样式会发生变化:
我找到了解决方案!
- 所有你必须为
MyApp.Android\Resources\values\colors.xml
中的浅色主题和 MyApp.Android\Resources\values-night\colors.xml
中的深色主题添加强调(或任何其他)颜色。然后在 styles.xml
<item name="colorAccent">@color/colorAccent</item>
的主题中按名称引用该颜色。
现在,当设备切换到深色主题时,强调色也会改变。
- 现在。如果您的应用程序中有手动主题控制怎么办?您可以强制 Android 显示浅色或深色主题的颜色。为共享项目添加类似界面:
namespace MyApp.Core.Models.InterplatformCommunication
{
public interface INightModeManager
{
NightModeStyle DefaultNightMode { get; set; }
}
public enum NightModeStyle
{
/// <summary>
/// An unspecified mode for night mode.
/// </summary>
Unspecified = -100,
/// <summary>
/// Mode which uses the system's night mode setting to determine if it is night or not.
/// </summary>
FollowSystem = -1,
/// <summary>
/// Night mode which uses always uses a light mode, enabling non-night qualified resources regardless of the time.
/// </summary>
No = 1,
/// <summary>
/// Night mode which uses always uses a dark mode, enabling night qualified resources regardless of the time.
/// </summary>
Yes = 2,
/// <summary>
/// Night mode which uses a dark mode when the system's 'Battery Saver' feature is enabled, otherwise it uses a 'light mode'.
/// </summary>
AutoBattery = 3
}
}
- 在 Android 项目中添加此实现。设置
AppCompatDelegate.DefaultNightMode
强制应用在不重启应用的情况下加载浅色或深色主题的资源。
[assembly: Xamarin.Forms.Dependency(typeof(NightModeManager))]
namespace MyApp.Droid.Dependences
{
public class NightModeManager : INightModeManager
{
public NightModeStyle DefaultNightMode
{
get => (NightModeStyle)AppCompatDelegate.DefaultNightMode;
set => AppCompatDelegate.DefaultNightMode = (int)value;
}
}
}
- 更改应用主题时添加此逻辑(
AppTheme
是自定义枚举):
private static void UpdateNativeStyle(AppTheme selectedTheme)
{
NightModeStyle style = selectedTheme switch
{
AppTheme.Dark => NightModeStyle.Yes,
AppTheme.Light => NightModeStyle.No,
AppTheme.FollowSystem => NightModeStyle.FollowSystem,
_ => throw new InvalidOperationException("Unsupported theme"),
};
var nightModeManager = DependencyService.Get<INightModeManager>();
nightModeManager.DefaultNightMode = style;
}
更多相关信息:
如旁注,设置后:
AppCompatDelegate.DefaultNightMode = ...
您需要重新创建 activity 才能将更改应用到当前页面:
activity.Recreate();
例如,如果您正在使用 Xamarin 的 CrossCurrentActivity 插件,您可以执行以下操作:
CrossCurrentActivity.Current.Activity.Recreate();
我将 Android 的强调色设置为灰色,因此它在任何主题(浅色或深色)中看起来都很正常。例如,灰色非常适合编辑控件,但事实证明它也用于警告取消按钮的文本。所以现在它在浅色主题中看起来很好,但在深色主题中非常糟糕。
如何从 Xamarin.Forms 应用动态更改 Android 的 colorAccent
?
编辑:这是 my theme changing code 目前的情况。 (我没有使用 AppThemeBinding
因为这种方法允许两个以上的主题)
你不能,因为强调色是在主题中定义的,而主题是 read-only。我假设动态意味着以编程方式。
在Xamarin Forms中,我们可以使用DependencyService to call native method. Fortunately, Android document provide the method setLocalNightMode来修改本地的DarkMode。需要注意的是,此方法不能修改手机设置的配置。
现在我们可以创建一个IDarkModeService
接口:
public interface IDarkModeService
{
void SetDarkMode(bool value);
}
然后在Android解决方案中实现它的方法:
public class DarkModeService : IDarkModeService
{
public void SetDarkMode(bool value)
{
if (value)
{
MainActivity.instance.Delegate.SetLocalNightMode(AppCompatDelegate.ModeNightYes);
MainActivity.instance.Recreate();
}
else
{
MainActivity.instance.Delegate.SetLocalNightMode(AppCompatDelegate.ModeNightNo);
MainActivity.instance.Recreate();
}
}
}
这里我们需要从MainActivity
创建一个静态的instance
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity instance { set; get; }
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
instance = this;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
}
}
并且不要忘记在 styles.xml
中添加配置以使应用程序支持 DarkMode:
<style name="MainTheme" parent="Theme.AppCompat.DayNight.NoActionBar"></style>
最后,我们可以调用Xamarin Forms中的依赖方法如下:
private async void ShowDialog_Clicked(object sender, EventArgs e)
{
await DisplayAlert("Alert", "You have been alerted", "OK");
}
private void SetDarkMode_Clicked(object sender, EventArgs e)
{
DependencyService.Get<IDarkModeService>().SetDarkMode(true);
}
private void CancelDarkMode_Clicked(object sender, EventArgs e)
{
DependencyService.Get<IDarkModeService>().SetDarkMode(false);
}
效果:
==================================更新======== ========================
如果需要自定义每个 Theme 的样式,可以在运行时交换 Theme。
首先,您可以在 Xamrin Forms 中存储一个主题标志(DarkMode):
private void SetDarkMode_Clicked(object sender, EventArgs e)
{
Preferences.Set("DarkMode", true);
DependencyService.Get<IDarkModeService>().SetDarkMode(true);
}
private void CancelDarkMode_Clicked(object sender, EventArgs e)
{
Preferences.Set("DarkMode", false);
DependencyService.Get<IDarkModeService>().SetDarkMode(false);
}
然后在里面添加每个Theme样式styles.xml:
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<style name="MainTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
</style>
<style name="DayTheme" parent="MainTheme">
</style>
<style name="NightTheme" parent="MainTheme" >
<item name="buttonBarPositiveButtonStyle">@style/positiveBtnStyle</item>
<item name="buttonBarNegativeButtonStyle">@style/negativeBtnstyle</item>
</style>
<!--style of sure button-->
<style name="positiveBtnStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
<item name="android:textColor">#0000ff</item>
</style>
<!--style of cancel button-->
<style name="negativeBtnstyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
<item name="android:textColor">#999999</item>
</style>
</resources>
最后,在MainActivity.cs中创建视图之前更改主题:
public static MainActivity instance { set; get; }
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
instance = this;
var darkMode = Preferences.Get("DarkMode", false);
if (darkMode)
{
this.SetTheme(Resource.Style.NightTheme);
}
else
{
this.SetTheme(Resource.Style.DayTheme);
}
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
现在我们可以看到按钮的颜色样式会发生变化:
我找到了解决方案!
- 所有你必须为
MyApp.Android\Resources\values\colors.xml
中的浅色主题和MyApp.Android\Resources\values-night\colors.xml
中的深色主题添加强调(或任何其他)颜色。然后在styles.xml
<item name="colorAccent">@color/colorAccent</item>
的主题中按名称引用该颜色。 现在,当设备切换到深色主题时,强调色也会改变。 - 现在。如果您的应用程序中有手动主题控制怎么办?您可以强制 Android 显示浅色或深色主题的颜色。为共享项目添加类似界面:
namespace MyApp.Core.Models.InterplatformCommunication
{
public interface INightModeManager
{
NightModeStyle DefaultNightMode { get; set; }
}
public enum NightModeStyle
{
/// <summary>
/// An unspecified mode for night mode.
/// </summary>
Unspecified = -100,
/// <summary>
/// Mode which uses the system's night mode setting to determine if it is night or not.
/// </summary>
FollowSystem = -1,
/// <summary>
/// Night mode which uses always uses a light mode, enabling non-night qualified resources regardless of the time.
/// </summary>
No = 1,
/// <summary>
/// Night mode which uses always uses a dark mode, enabling night qualified resources regardless of the time.
/// </summary>
Yes = 2,
/// <summary>
/// Night mode which uses a dark mode when the system's 'Battery Saver' feature is enabled, otherwise it uses a 'light mode'.
/// </summary>
AutoBattery = 3
}
}
- 在 Android 项目中添加此实现。设置
AppCompatDelegate.DefaultNightMode
强制应用在不重启应用的情况下加载浅色或深色主题的资源。
[assembly: Xamarin.Forms.Dependency(typeof(NightModeManager))]
namespace MyApp.Droid.Dependences
{
public class NightModeManager : INightModeManager
{
public NightModeStyle DefaultNightMode
{
get => (NightModeStyle)AppCompatDelegate.DefaultNightMode;
set => AppCompatDelegate.DefaultNightMode = (int)value;
}
}
}
- 更改应用主题时添加此逻辑(
AppTheme
是自定义枚举):
private static void UpdateNativeStyle(AppTheme selectedTheme)
{
NightModeStyle style = selectedTheme switch
{
AppTheme.Dark => NightModeStyle.Yes,
AppTheme.Light => NightModeStyle.No,
AppTheme.FollowSystem => NightModeStyle.FollowSystem,
_ => throw new InvalidOperationException("Unsupported theme"),
};
var nightModeManager = DependencyService.Get<INightModeManager>();
nightModeManager.DefaultNightMode = style;
}
更多相关信息:
如旁注,设置后:
AppCompatDelegate.DefaultNightMode = ...
您需要重新创建 activity 才能将更改应用到当前页面:
activity.Recreate();
例如,如果您正在使用 Xamarin 的 CrossCurrentActivity 插件,您可以执行以下操作:
CrossCurrentActivity.Current.Activity.Recreate();