【问题标题】:Dynamically change android's accent color动态改变android的强调色
【发布时间】:2020-10-08 06:06:06
【问题描述】:

我将 Android 的强调色设置为灰色,因此它在任何主题(浅色或深色)中看起来都很正常。例如,灰色非常适合编辑控件,但事实证明它也用于警报取消按钮的文本。所以现在它在浅色主题中看起来不错,但在深色主题中却很糟糕。

如何从 Xamarin.Forms 应用动态更改 Android 的 colorAccent

编辑:截至目前,这里是my theme changing code。 (我没有使用AppThemeBinding,因为这种方法允许两个以上的主题)

【问题讨论】:

    标签: android xamarin.forms themes


    【解决方案1】:

    您不能,因为主题色是在主题中定义的,而主题是只读的。我认为动态意味着以编程方式。

    【讨论】:

    • 是的,我的意思是编程。好的,那么我可以在 android 项目中定义几个主题并以编程方式更改它们吗? PS:在问题描述中添加了我的应用程序中的代码。也许会有所帮助
    【解决方案2】:

    在 Xamarin Forms 中,我们可以使用 DependencyService 来调用原生方法。幸运的是,Android 文档提供了setLocalNightMode 方法来修改本地的DarkMode。需要注意的是,这个方法不能修改移动端Settings的配置。

    现在我们可以创建一个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);
    }
    

    效果:

    ===================================更新============ =======================

    如果需要自定义每个主题的样式,可以在运行时交换主题

    首先,您可以在 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);
    }
    

    然后在 styles.xml 中添加每个 Theme 样式:

    <?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());
    }
    

    现在我们可以看到按钮的颜色样式会发生变化:

    【讨论】:

    • 感谢您提供如此详细的回答,但这不是我需要的。在您的示例中,强调颜色不会改变(警报的确定按钮的颜色保持不变)。我已经有在我的应用程序中更改主题的功能。我唯一不能改变的是强调色
    • PS:在问题描述中添加了我的应用程序中的代码。也许会有所帮助
    • @МаксимКошевой 好的,我会检查的。如果更新答案将在此处标记。
    • @МаксимКошевой 我已经更新了答案,你有时间可以看看。如果回复有帮助,请不要忘记采纳为答案(点击此答案左上角的✔),对有类似问题的其他人有帮助。
    • 感谢您的更新。刚刚注意到,在您的示例中,您重新创建了主题更改的视图。那么,如果用户更改主题,它实际上会重新启动应用程序(所有未保存的更改和打开的页面都会丢失)?这不好,因为在 android 10+ 上,深色主题可以按计划进行并且可以自动激活。因此,如果应用程序只是在某事中间重新启动,那将不会是良好的用户体验。抱歉,如果我误解了什么,之前从未手动重新创建过视图,所以不知道会发生什么
    【解决方案3】:

    我找到了解决办法!

    1. 您必须在MyApp.Android\Resources\values\colors.xml 中为浅色主题添加重音(或任何其他)颜色,在MyApp.Android\Resources\values-night\colors.xml 中添加深色主题。然后在 styles.xml &lt;item name="colorAccent"&gt;@color/colorAccent&lt;/item&gt; 的主题中按名称引用该颜色。 现在,当设备切换到深色主题时,强调色也会发生变化。
    2. 现在。如果您的应用程序中有手动主题控制怎么办?您可以强制 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
        }
    }
    
    1. 在 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;
            }
        }
    }
    
    1. 在更改应用主题时添加此逻辑(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;
            }
    

    更多信息:

    【讨论】:

      【解决方案4】:

      作为旁注,设置后:

      AppCompatDelegate.DefaultNightMode = ... 
      

      您需要重新创建活动以将更改应用到当前页面:

      activity.Recreate();
      

      例如,如果您使用 Xamarin 的 CrossCurrentActivity 插件,您可以这样做:

      CrossCurrentActivity.Current.Activity.Recreate();
      

      【讨论】:

      • 一切都对我有用,无需重新创建活动。您的目标是什么 SDK?
      • API 级别 29 - Android 10
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-24
      • 1970-01-01
      • 1970-01-01
      • 2018-12-31
      • 2011-05-19
      • 2019-09-10
      • 2013-04-25
      相关资源
      最近更新 更多