美文网首页Android OtherUI效果
【官方推荐方式】【原创】安卓换肤踩坑纯色模式app使用attr轻

【官方推荐方式】【原创】安卓换肤踩坑纯色模式app使用attr轻

作者: 吉凶以情迁 | 来源:发表于2022-04-13 09:46 被阅读0次

    如果在网上搜换肤,方案五花八门,但是根据app的需求,以及无设计师的情况下,基本上简约风格app,这种风格下只需要几个颜色就行了,根本不需要动态从磁盘加载皮肤apk,而且通过反射操作侵入性太强,因此attr大法才是最适合目前的我所做的app实现。

    网上的换肤方法侵入性太强,而纯色app不需要各种花式的皮肤,基本上2三套颜色就行了,主色,次色,而其他则非黑即白。深色模式实现就更简单了,用着色tint就实现了。

    经过了几天的研究发现,动态修改setTheme是有bug的, bug就是状态栏颜色和actionbar在未在activity定义attr背景的情况下实现修改actionbar的就有这个bug,2015年在stackoverflow网站上就有人提出解决方法,这个解决方法是没有办法的方法,需要在baseactivity进行判断,如果有actionbar就设置actionbar颜色,

    以及设置状态栏颜色。

    达到的效果

    在颜色选择器中是可以直接使用实现的属性?attr
    而在drawable,则需要包裹一层drawable引用color,直接使用color属性也是会报错的,
    正常的按钮,对话框,控件不需要再通过代码,xml设置颜色,

    而网上的操作性太麻烦,正规的写法就是官方的写法,能不在view xml定义的就不在view xml定义
    这样侵入性比较小。

    颜色主题需要注意的事项

    drawable要使用颜色属性只能包裹一层shape

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="?attr/defaultThemeColorSecond"/>
    </shape>
    

    第三方自定义ui 有的是只支持颜色不支持attr的。则需要进行额外适配处理,
    其处理方式就是根据属性查找对应的颜色 或者id (colorres)
    颜色属性找颜色

        public static int attrFetchColor(Context context,int attrColor) {
            int[] attribute = new int[]{attrColor};
            TypedArray array =context.getTheme().obtainStyledAttributes(attribute);
            int color = array.getColor(0, AppContext.getInstance().getResources().getColor(R.color.themeColor));
            array.recycle();
            return color;
        }
    
    

    查找id

    
      public static int attrFetchColorId(Context context,int attrColor) {
            int[] attribute = new int[]{attrColor};
            TypedArray array = context.obtainStyledAttributes(attribute);
            int colorID = array.getResourceId(0, R.color.themeColor);
            array.recycle();
            return colorID;
        }
    
    
    

    在baseactivity onCreate中修改状态栏颜色

    
        public static void updateActionBarAndStatusColor(Activity activity) {
            if (activity instanceof AppCompatActivity) {
                AppCompatActivity appCompatActivity = (AppCompatActivity) activity;
                ActionBar supportActionBar = appCompatActivity.getSupportActionBar();
                if (supportActionBar != null) {
                    int i = AppUtils.attrFetchColor(activity,R.attr.defaultThemeColor);
                    supportActionBar.setBackgroundDrawable(new ColorDrawable(i));
                }
    
            }
            android.app.ActionBar actionBar = activity.getActionBar();
            if (actionBar != null) {
                int color = AppUtils.attrFetchColor(activity,R.attr.defaultThemeColor);
                actionBar.setBackgroundDrawable(new ColorDrawable(color));
            }
    
            if (Build.VERSION.SDK_INT >= 21) {
    //            getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    //            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                int statusBarBackground = AppUtils.attrFetchColor(activity,R.attr.colorPrimaryDark);
    
    
                Window window = activity.getWindow();
    //            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    //            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    //            window.setStatusBarColor(backgroundColor);
                window.setStatusBarColor(statusBarBackground);
            }
    
    
        }
    

    主题修改代码

     getBinding().rlMyThemeSetting.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                    int currentMode = NightModeUtils.Companion.getSpfThemeMode(AppContext.getInstance());
                    ThemeMode[] values = ThemeMode.values();
                    CharSequence[] items=new CharSequence[values.length];
                    for (int i = 0; i < values.length; i++) {
                        String title = AppContext.getInstance().getString(values[i].getStringValueId());
                        items[i]=title;
                    }
                    builder.setSingleChoiceItems(items, currentMode, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if (which != currentMode) {
                                dialog.dismiss();
                                ThemeMode value = values[which];
                                NightModeUtils.getInstance(AppContext.getInstance()).setThemeMode(value);
                                EventBus.getDefault().post(new ThemeChangeEvent().themeChange());
    
                            }
    
                        }
    
                    });
                    builder.setTitle(AppContext.getStr(R.string.deep_color_theme_setting));
                    builder.show();
    
                }
            });
    

    收到事件进行recreate(); ,我这里是在mainact,mainact可直接recreate,无需finish
    适配起来挺快的,通过各种批量替换
    但是需要注意的是,第三方对颜色适配做的很烂,哪怕大家众所周知的smartrefresh也不支持属性引用颜色。 因此主要的适配就是处理第三方框架的问题,
    这个适配工作基本上一天就搞定了。
    另外花的实际是纠结研究为啥actionbar和状态栏颜色通过setTheme无效花费了很多时间,在attach里面替换,以及研究theme的各种方法,以及引用再引用的方式也解决不了问题,
    最后既然无效我只能另外走方法了,强制设置。

    attr.xml定义

        <attr name="defaultThemeColor" format="reference|color"></attr>
        <attr name="defaultThemeColorSecond" format="reference|color"></attr>
    

    其实现在每一个主题都实现了,

    下面附上theme.xml 仔细看 都实现了defaultThemeColor defaultThemeColorSecond 属性,

    <?xml version="1.0" encoding="utf-8"?>
    <resources xmlns:tools="http://schemas.android.com/tools">
    
        <style name="Theme.MyApplication.Blue" parent="Theme.MyApplication.RootTheme">
            <item name="defaultThemeColor">@color/themeColorBlue</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecondBlue</item>
            <item name="android:buttonStyle">@style/Widget.AppCompat.Button.Small</item>
            <item name="colorButtonNormal">@color/themeColorBlue</item>
            <!--    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.Light.DarkActionBar">-->
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/themeColorBlue</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDarkBlue</item>
            <item name="colorPrimaryVariant">@color/colorPrimaryVariantBlue</item>
            <item name="colorOnPrimary">@color/colorOnPrimaryBlue</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/colorSecondary</item>
            <item name="colorAccent">@color/colorAccentBlue</item>
            <!--        <item name="colorSecondary">@color/teal_200</item>-->
            <item name="colorSecondaryVariant">@color/colorSecondaryVariant</item>
            <item name="colorOnSecondary">@color/colorOnSecondary</item>
            <!-- Status bar color. -->
            <item name="android:statusBarColor" tools:targetApi="lollipop"> @color/colorPrimaryDarkBlue</item>
            <item name="statusBarBackground">@color/colorPrimaryDarkBlue</item>
        </style>
    
        <style name="Theme.MyApplication.Yellow" parent="Theme.MyApplication.RootTheme">
            <item name="defaultThemeColor">@color/themeColorYellow</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecondYellow</item>
            <item name="android:buttonStyle">@style/Widget.AppCompat.Button.Small</item>
            <item name="colorButtonNormal">@color/themeColorYellow</item>
    
            <!--    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.Light.DarkActionBar">-->
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/themeColorYellow</item>
            <item name="colorAccent">@color/colorAccentYellow</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDarkYellow</item>
            <item name="colorPrimaryVariant">@color/colorPrimaryVariantYellow</item>
            <item name="colorOnPrimary">@color/colorOnPrimaryYellow</item>
    
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/colorSecondary</item>
            <!--        <item name="colorSecondary">@color/teal_200</item>-->
            <item name="colorSecondaryVariant">@color/colorSecondaryVariant</item>
            <item name="colorOnSecondary">@color/colorOnSecondary</item>
            <!-- Status bar color. -->
            <item name="android:statusBarColor">@color/colorPrimaryVariantYellow</item>
            <item name="controlBackground">@color/colorPrimaryDarkYellow</item>
            <item name="statusBarBackground">@color/colorPrimaryDarkYellow</item>
        </style>
    
    
    
        <style name="Theme.MyApplication.GREEN" parent="Theme.MyApplication.RootTheme">
            <item name="defaultThemeColor">@color/themeColorGreen</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecondGreen</item>
            <item name="android:buttonStyle">@style/Widget.AppCompat.Button.Small</item>
            <item name="colorButtonNormal">@color/themeColorGreen</item>
            <!--    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.Light.DarkActionBar">-->
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/themeColorGreen</item>
            <item name="colorAccent">@color/colorAccentGreen</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDarkGreen</item>
            <item name="colorPrimaryVariant">@color/colorPrimaryVariantGreen</item>
            <item name="colorOnPrimary">@color/colorOnPrimaryGreen</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/colorSecondary</item>
            <!--        <item name="colorSecondary">@color/teal_200</item>-->
            <item name="colorSecondaryVariant">@color/colorSecondaryVariant</item>
            <item name="colorOnSecondary">@color/colorOnSecondary</item>
            <!-- Status bar color. -->
            <item name="android:statusBarColor" tools:targetApi="lollipop">@color/colorPrimaryDarkGreen </item>
            <item name="statusBarBackground">@color/colorPrimaryDarkGreen </item>
    
        </style>
    
    
    
    
    
        <style name="Theme.MyApplication.PURPLE" parent="Theme.MyApplication.RootTheme">
            <item name="defaultThemeColor">@color/themeColorPurple</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecondPurple</item>
            <item name="android:buttonStyle">@style/Widget.AppCompat.Button.Small</item>
            <item name="colorButtonNormal">@color/themeColorPurple</item>
            <!--    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.Light.DarkActionBar">-->
    
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/themeColorPurple</item>
            <item name="colorAccent">@color/colorAccentPurple</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDarkPurple</item>
            <item name="colorPrimaryVariant">@color/colorPrimaryVariantPurple</item>
            <item name="colorOnPrimary">@color/colorOnPrimaryPurple</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/colorSecondary</item>
            <!--        <item name="colorSecondary">@color/teal_200</item>-->
            <item name="colorSecondaryVariant">@color/colorSecondaryVariant</item>
            <item name="colorOnSecondary">@color/colorOnSecondary</item>
            <!-- Status bar color. -->
            <item name="statusBarBackground">@color/themeColorPurple</item>
            <item name="android:statusBarColor">@color/colorPrimaryDarkPurple</item>
    
        </style>
    
    
    
    
    
        <style name="Theme.MyApplication.Amber" parent="Theme.MyApplication.RootTheme">
            <item name="defaultThemeColor">@color/themeColorAmber</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecondAmber</item>
            <item name="android:buttonStyle">@style/Widget.AppCompat.Button.Small</item>
            <item name="colorButtonNormal">@color/themeColorAmber</item>
            <!--    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.Light.DarkActionBar">-->
    
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/themeColorAmber</item>
            <item name="colorAccent">@color/colorAccentAmber</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDarkAmber</item>
            <item name="colorPrimaryVariant">@color/colorPrimaryVariantAmber</item>
            <item name="colorOnPrimary">@color/colorOnPrimaryAmber</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/colorSecondary</item>
            <!--        <item name="colorSecondary">@color/teal_200</item>-->
            <item name="colorSecondaryVariant">@color/colorSecondaryVariant</item>
            <item name="colorOnSecondary">@color/colorOnSecondary</item>
            <!-- Status bar color. -->
            <item name="statusBarBackground">@color/themeColorAmber</item>
            <item name="android:statusBarColor">@color/colorPrimaryDarkAmber</item>
        </style>
    
        <style name="Theme.MyApplication.Cyan" parent="Theme.MyApplication.RootTheme">
            <item name="defaultThemeColor">@color/themeColorCyan</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecondCyan</item>
            <item name="android:buttonStyle">@style/Widget.AppCompat.Button.Small</item>
            <item name="colorButtonNormal">@color/themeColorCyan</item>
            <!--    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.Light.DarkActionBar">-->
    
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/themeColorCyan</item>
            <item name="colorAccent">@color/colorAccentCyan</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDarkCyan</item>
            <item name="colorPrimaryVariant">@color/colorPrimaryVariantCyan</item>
            <item name="colorOnPrimary">@color/colorOnPrimaryCyan</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/colorSecondary</item>
            <!--        <item name="colorSecondary">@color/teal_200</item>-->
            <item name="colorSecondaryVariant">@color/colorSecondaryVariant</item>
            <item name="colorOnSecondary">@color/colorOnSecondary</item>
            <!-- Status bar color. -->
            <item name="statusBarBackground">@color/themeColorCyan</item>
            <item name="android:statusBarColor">@color/colorPrimaryDarkCyan</item>
        </style>
    
    
    
    
    
    
        <style name="Theme.MyApplication.Brown" parent="Theme.MyApplication.RootTheme">
            <item name="defaultThemeColor">@color/themeColorBrown</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecondBrown</item>
            <item name="android:buttonStyle">@style/Widget.AppCompat.Button.Small</item>
            <item name="colorButtonNormal">@color/themeColorBrown</item>
            <!--    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.Light.DarkActionBar">-->
    
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/themeColorBrown</item>
            <item name="colorAccent">@color/colorAccentBrown</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDarkBrown</item>
            <item name="colorPrimaryVariant">@color/colorPrimaryVariantBrown</item>
            <item name="colorOnPrimary">@color/colorOnPrimaryBrown</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/colorSecondary</item>
            <!--        <item name="colorSecondary">@color/teal_200</item>-->
            <item name="colorSecondaryVariant">@color/colorSecondaryVariant</item>
            <item name="colorOnSecondary">@color/colorOnSecondary</item>
            <!-- Status bar color. -->
            <item name="statusBarBackground">@color/themeColorBrown</item>
            <item name="android:statusBarColor">@color/colorPrimaryDarkBrown</item>
    
        </style>
    
    
    
    
    
    
    
    
        <style name="Theme.MyApplication.Grey" parent="Theme.MyApplication.RootTheme">
            <item name="defaultThemeColor">@color/themeColorGrey</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecondGrey</item>
            <item name="android:buttonStyle">@style/Widget.AppCompat.Button.Small</item>
            <item name="colorButtonNormal">@color/themeColorGrey</item>
            <!--    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.Light.DarkActionBar">-->
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/themeColorGrey</item>
            <item name="colorAccent">@color/colorAccentGrey</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDarkGrey</item>
            <item name="colorPrimaryVariant">@color/colorPrimaryVariantGrey</item>
            <item name="colorOnPrimary">@color/colorOnPrimaryGrey</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/colorSecondary</item>
            <!--        <item name="colorSecondary">@color/teal_200</item>-->
            <item name="colorSecondaryVariant">@color/colorSecondaryVariant</item>
            <item name="colorOnSecondary">@color/colorOnSecondary</item>
            <!-- Status bar color. -->
            <item name="statusBarBackground">@color/themeColorGrey</item>
            <item name="android:statusBarColor">@color/colorPrimaryDarkGrey</item>
        </style>
    
    
    
    
        <style name="Theme.MyApplication.DeepOrange" parent="Theme.MyApplication.RootTheme">
            <item name="defaultThemeColor">@color/themeColorDeepOrange</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecondDeepOrange</item>
            <item name="android:buttonStyle">@style/Widget.AppCompat.Button.Small</item>
            <item name="colorButtonNormal">@color/themeColorDeepOrange</item>
            <!--    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.Light.DarkActionBar">-->
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/themeColorDeepOrange</item>
            <item name="colorAccent">@color/colorAccentDeepOrange</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDarkDeepOrange</item>
            <item name="colorPrimaryVariant">@color/colorPrimaryVariantDeepOrange</item>
            <item name="colorOnPrimary">@color/white_no_night</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/colorSecondary</item>
            <!--        <item name="colorSecondary">@color/teal_200</item>-->
            <item name="colorSecondaryVariant">@color/colorSecondaryVariantOrange</item>
            <item name="colorOnSecondary">@color/colorOnSecondary</item>
            <!-- Status bar color. -->
            <item name="statusBarBackground">@color/themeColorDeepOrange</item>
            <item name="android:statusBarColor">@color/colorPrimaryDarkDeepOrange</item>
        </style>
        <style name="Theme.MyApplication.NotImpl" parent="Theme.AppCompat.DayNight.DarkActionBar">
            <item name="defaultThemeColor">@color/themeColor</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecond</item>
            <item name="colorPrimary">?attr/defaultThemeColorSecond</item>
            <item name="colorPrimaryDark">?attr/defaultThemeColor</item>
            <item name="colorAccent">?attr/defaultThemeColorSecond</item>
        </style>
    
        <style name="Theme.MyApplication.DefaultBlue" parent="Theme.MyApplication.RootTheme">
            <!-- Primary brand color. -->
            <item name="defaultThemeColor">@color/themeColor</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecond</item>
            <!--        style设置没效果代码批量设置-->
            <item name="colorButtonNormal">?attr/defaultThemeColorSecond</item>
            <item name="android:elevation">0dp</item>
            <!--        hide shadow-->
            <item name="android:windowContentOverlay">@null</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
            <item name="colorAccent">@color/colorAccent</item>
            <item name="colorOnPrimary">@color/colorOnPrimary</item>
    
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/colorSecondary</item>
            <item name="colorSecondaryVariant">@color/colorSecondaryVariant</item>
            <item name="colorOnSecondary">@color/colorOnSecondary</item>
            <!-- Status bar color. -->
    <!--        <item name="android:statusBarColor">@color/colorPrimaryDark</item>-->
    <!--        <item name="statusBarBackground">@color/colorPrimaryDark</item>-->
            <!-- Customize your theme here. -->
        </style>
    
    
        <style name="Theme.MyApplication.DefaultBlue.Global" parent="Theme.MyApplication.RootTheme">
            <item name="defaultThemeColor">@color/themeColor</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecond</item>
        </style>
    
        <style name="Theme.MyApplication.BLACK" parent="Theme.MyApplication.RootTheme">
            <item name="defaultThemeColor">@color/themeColorBlack</item>
            <item name="defaultThemeColorSecond">@color/themeColorSecondBlack</item>
            <item name="android:buttonStyle">@style/Widget.AppCompat.Button.Small</item>
            <item name="colorButtonNormal">@color/themeColorBlack</item>
            <!--    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.Light.DarkActionBar">-->
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/themeColorSecondBlack</item>
            <item name="colorPrimaryDark">@color/themeColorSecondBlack</item>
            <item name="colorPrimaryVariant">@color/colorPrimaryVariantBlack</item>
            <item name="colorOnPrimary">@color/colorOnPrimaryBlack</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/colorSecondary</item>
            <!--        <item name="colorSecondary">@color/teal_200</item>-->
            <item name="colorSecondaryVariant">@color/themeColorSecondBlack</item>
            <item name="colorOnSecondary">@color/colorOnSecondary</item>
            <!-- Status bar color. -->
            <item name="android:statusBarColor" tools:targetApi="lollipop"> @color/colorPrimaryVariantBlack</item>
            <item name="statusBarBackground">@color/themeColorBlack</item>
    
        </style>
    
    
    
    
    
        <style name="Theme.MyApplication.BLACK.NoActionBar" parent="Theme.MyApplication.BLACK">
            <item name="windowActionBar">false</item>
            <item name="android:windowActionBar">false</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:actionMenuTextColor">@color/white_no_night</item>
            <item name="windowNoTitle">true</item>
        </style>
    
    
    
        <style name="Theme.MyApplication.DefaultBlue.NoActionBar" parent="Theme.MyApplication.DefaultBlue">
            <item name="windowActionBar">false</item>
            <item name="android:windowActionBar">false</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:actionMenuTextColor">@color/white_no_night</item>
            <item name="windowNoTitle">true</item>
        </style>
    
        <style name="Theme.MyApplication.Amber.NoActionBar" parent="Theme.MyApplication.Amber">
            <item name="windowActionBar">false</item>
            <item name="android:windowActionBar">false</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:actionMenuTextColor">@color/white_no_night</item>
            <item name="windowNoTitle">true</item>
        </style>
    
    
        <style name="Theme.MyApplication.GREEN.NoActionBar" parent="Theme.MyApplication.GREEN">
            <item name="windowActionBar">false</item>
            <item name="android:windowActionBar">false</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:actionMenuTextColor">@color/white_no_night</item>
            <item name="windowNoTitle">true</item>
        </style>
    
    
    
        <style name="Theme.MyApplication.PURPLE.NoActionBar" parent="Theme.MyApplication.PURPLE">
            <item name="windowActionBar">false</item>
            <item name="android:windowActionBar">false</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:actionMenuTextColor">@color/white_no_night</item>
            <item name="windowNoTitle">true</item>
        </style>
        <style name="Theme.MyApplication.Grey.NoActionBar" parent="Theme.MyApplication.Grey">
            <item name="windowActionBar">false</item>
            <item name="android:windowActionBar">false</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:actionMenuTextColor">@color/white_no_night</item>
            <item name="windowNoTitle">true</item>
        </style>
    
        <style name="Theme.MyApplication.Yellow.NoActionBar" parent="Theme.MyApplication.Yellow">
            <item name="windowActionBar">false</item>
            <item name="android:windowActionBar">false</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:actionMenuTextColor">@color/white_no_night</item>
            <item name="windowNoTitle">true</item>
        </style>
        <style name="Theme.MyApplication.Blue.NoActionBar" parent="Theme.MyApplication.Blue">
            <item name="windowActionBar">false</item>
            <item name="android:windowActionBar">false</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:actionMenuTextColor">@color/white_no_night</item>
            <item name="windowNoTitle">true</item>
        </style>
    
        <style name="Theme.MyApplication.Brown.NoActionBar" parent="Theme.MyApplication.Brown">
            <item name="windowActionBar">false</item>
            <item name="android:windowActionBar">false</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:actionMenuTextColor">@color/white_no_night</item>
            <item name="windowNoTitle">true</item>
        </style>
    
        <style name="Theme.MyApplication.Cyan.NoActionBar" parent="Theme.MyApplication.Cyan">
            <item name="windowActionBar">false</item>
            <item name="android:windowActionBar">false</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:actionMenuTextColor">@color/white_no_night</item>
            <item name="windowNoTitle">true</item>
        </style>
        <style name="Theme.MyApplication.DeepOrange.NoActionBar" parent="Theme.MyApplication.DeepOrange">
            <item name="windowActionBar">false</item>
            <item name="android:windowActionBar">false</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:actionMenuTextColor">@color/white_no_night</item>
            <item name="windowNoTitle">true</item>
        </style>
    
    </resources>
    
    

    root.

        <style name="Theme.MyApplication.RootTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        </style>
    

    color实现

     <color name="themeColor">#5768FE</color>
        <color name="printtestcolor">#f2c4c4</color>
    
        <color name="themeColorSecond">#5766FF</color>
    
        <!--
            <color name="themeColor" >#1D4C78</color>
            <color name="themeColorSecond" >#1F4E7A</color>-->
    <!--    http://mcg.mbitson.com/#!?mcgpalette0=%235768fe  根据颜色找出更深的或者更淡淡的颜色-->
        <color name="colorPrimary">@color/themeColor</color>
        <color name="colorPrimaryDark">#4F60FE</color>
        <color name="colorAccent">#536DFE</color>
        <color name="colorPrimaryVariant">@color/themeColor</color>
        <color name="colorOnPrimary">@color/white</color>
    
    
        <color name="colorSecondary">@color/light_blue_disable</color>
        <color name="colorSecondaryVariant">@color/teal_700</color>
        <color name="colorOnSecondary">@color/black</color>
    
        <color name="themeColorPurple">@color/purple_300</color>
        <color name="colorAccentPurple">#E040FB</color>
        <color name="themeColorSecondPurple">@color/purple_300</color>
        <color name="colorPrimaryPurple">@color/purple_300</color>
        <color name="colorPrimaryDarkPurple">#7B1FA2</color>
        <color name="colorPrimaryVariantPurple">@color/purple_300</color>
        <color name="colorOnPrimaryPurple">@color/white</color>
    
    
    
        <color name="themeColorYellow">#FF9800</color>
        <color name="themeColorSecondYellow">#FF9800</color>
        <color name="colorPrimaryYellow">#F57C00</color>
        <color name="colorPrimaryDarkYellow">#FF9800</color>
        <color name="colorAccentYellow">#FF9800</color>
        <color name="colorPrimaryVariantYellow">#FF9800</color>
        <color name="colorOnPrimaryYellow">@color/white</color>
    
    
    
        <color name="themeColorGreen">@color/green_700</color>
        <color name="themeColorSecondGreen">@color/green_700</color>
        <color name="colorPrimaryGreen">@color/green_700</color>
        <color name="colorPrimaryDarkGreen">#388E3C</color>
        <color name="colorAccentGreen">#4CAF50</color>
        <color name="colorPrimaryVariantGreen">@color/green_700</color>
        <color name="colorOnPrimaryGreen">@color/white</color>
    
    
    
    
        <color name="themeColorBlue">@color/blue_900</color>
        <color name="themeColorSecondBlue">@color/blue_900</color>
        <color name="colorPrimaryBlue">@color/blue_900</color>
        <color name="colorPrimaryDarkBlue">@color/blue_900</color>
        <color name="colorAccentBlue">#448AFF</color>
        <color name="colorPrimaryVariantBlue">@color/blue_900</color>
        <color name="colorOnPrimaryBlue">@color/white</color>
    
    
        <color name="themeColorBlack">@color/quantum_black_100</color>
        <color name="themeColorSecondBlack">@color/quantum_black_100</color>
        <color name="colorPrimaryBlack">@color/quantum_black_100</color>
        <color name="colorPrimaryAccent">#5D4037</color>
        <color name="colorPrimaryVariantBlack">@color/quantum_black_100</color>
        <color name="colorOnPrimaryBlack">@color/white</color>
    
    
    
        <color name="themeColorBrown" >#795548</color>
        <color name="themeColorSecondBrown" >#795548</color>
        <color name="colorAccentBrown">#9E9E9E</color>
        <color name="colorPrimaryDarkBrown">#5D4037</color>
        <color name="colorPrimaryVariantBrown">@color/black_overlay</color>
        <color name="colorOnPrimaryBrown">@color/black</color>
    
    
        <color name="themeColorTeal" >#009688</color>
        <color name="themeColorSecondTeal" >#757575</color>
        <color name="colorAccentTeal">#00BCD4</color>
        <color name="colorPrimaryDarkTeal">#00796B</color>
        <color name="colorPrimaryVariantTeal">@color/black_overlay</color>
        <color name="colorOnPrimaryTeal">@color/black</color>
    
        <color name="themeColorCyan" >#00BCD4</color>
        <color name="themeColorSecondCyan" >#0097A7</color>
        <color name="colorAccentCyan">#009688</color>
        <color name="colorPrimaryDarkCyan">#0097A7</color>
        <color name="colorPrimaryVariantCyan">#B2EBF2</color>
        <color name="colorOnPrimaryCyan">#FFFFFF</color>
    
        <color name="themeColorAmber" >#FFC107</color>
        <color name="themeColorSecondAmber" >#FFC107</color>
        <color name="colorAccentAmber">#FFC107</color>
        <color name="colorPrimaryDarkAmber">#FFA000</color>
        <color name="colorPrimaryVariantAmber">#212121</color>
        <color name="colorOnPrimaryAmber">#212121</color>
    
        <color name="themeColorDeepOrange" >#FF5722</color>
        <color name="themeColorSecondDeepOrange" >#FF5722</color>
        <color name="colorAccentDeepOrange">#FF4081</color>
        <color name="colorPrimaryDarkDeepOrange">#E64A19</color>
        <color name="colorPrimaryVariantDeepOrange">#212121</color>
        <color name="colorOnPrimaryDeepOrange">#212121</color>
        <color name="colorSecondaryVariantOrange">#E64A19</color>
    
        <color name="themeColorGrey" >#607D8B</color>
        <color name="themeColorSecondGrey" >#757575</color>
        <color name="colorAccentGrey">#9E9E9E</color>
        <color name="colorPrimaryDarkGrey">#455A64</color>
        <color name="colorPrimaryVariantGrey">@color/black_overlay</color>
        <color name="colorOnPrimaryGrey">@color/black</color>
    
    
    
    
    image.png
    image.png

    深色主题values-night themes.xml
    把正常颜色的拷贝过来然后指定颜色就行了,
    修改主题的代码 baseactivityonCreate调用在setContentView之前

      fun applySetting(context: Context?): Int {
            var themeId = 0;
            // 检查主题
            val themeModeInt = getSpfThemeMode()
            val themeMode = ThemeMode.parseOfInt(themeModeInt)
            var disableActionBar: Boolean = false;
            var actName: String = "";
            var needActionBar:Int =-1;
            if (context is BaseActivity) {
                needActionBar = context.needActionBar()
                if( needActionBar == 1) {
                    disableActionBar = false;
                }else if( needActionBar == 0) {
                    disableActionBar = true;
                }
            }
                actName =  context?.javaClass?.simpleName + " ,是否禁用actionBar " + disableActionBar;
            if (context is AppCompatActivity) {
                if (needActionBar==-1) {
                    var act: AppCompatActivity = context;
                    disableActionBar = if(act.supportActionBar!=null) true else true;//act.supportActionBar is WindowDecorActionBar
                }
            }
            Log.w("ThemeStyle", "主题模式 ${themeMode.name} act $actName");
    
            if (themeMode == ThemeMode.BLUE_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Blue_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_Blue
                }
            } else if (themeMode == ThemeMode.YELLOW_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Yellow_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_Yellow
                }
            } else if (themeMode == ThemeMode.PURPLE_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_PURPLE_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_PURPLE
                }
            } else if (themeMode == ThemeMode.GREEN_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_GREEN_NoActionBar;
                } else {
                    themeId = R.style.Theme_MyApplication_GREEN
                }
            } else if (themeMode == ThemeMode.GREY_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Grey_NoActionBar;
                } else {
                    themeId = R.style.Theme_MyApplication_Grey
                }
            } else if (themeMode == ThemeMode.BROWN_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Brown_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_Brown
                }
            } else if (themeMode == ThemeMode.DEEP_ORANGE_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_DeepOrange_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_DeepOrange
                }
            } else if (themeMode == ThemeMode.AMBER_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Amber_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_Amber
                }
            } else if (themeMode == ThemeMode.CYAN_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Cyan_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_Cyan
                }
            } else if (themeMode == ThemeMode.BLACK_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_BLACK_NoActionBar;
                } else {
                    themeId = R.style.Theme_MyApplication_BLACK;
                }
            } else {
                if (disableActionBar) {//如果appcontext设置actionbar,act manifest.xml没有声明解除actionbar,然后调用setSupportBar则会抛出异常,因此需要处理适配。
                    themeId = R.style.Theme_MyApplication_DefaultBlue_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_DefaultBlue
                }
            }
    
            if (themeId != 0) {
                context?.setTheme(themeId)
    //            return themeId;
            }
            AppCompatDelegate.setDefaultNightMode(
                when (themeMode) {
                    ThemeMode.MODE_ALWAYS_ON -> AppCompatDelegate.MODE_NIGHT_YES
                    ThemeMode.MODE_ALWAYS_OFF -> AppCompatDelegate.MODE_NIGHT_NO
                    ThemeMode.MODE_FOLLOW_SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
                    else -> {
                        AppCompatDelegate.MODE_NIGHT_NO
                    }
                }
    
    
            )
            return themeId
    
        }
    

    如果不为0,

        if (color != 0) {
    //            getTheme().applyStyle(color, true);
                AppUtils.updateActionBarAndStatusColor(this);
            }
    

    另外补充一点,按钮这些一般我都没有修改在每一个activity xml设置的,遵循material design以及theme的写法,全局就可以进行操作的,在<item name="colorPrimary">就完成了适配,
    主要的适配工作还是处理selector的颜色以及第三方框架引用了颜色的情况,另外处理深色兼容的适配。

    另外关于重启生效的事情,recreate也是只能修改部分颜色而在我自己曾经写的一款app没有这样的问题,经过比较发现,我的那个app没有一个app是额外指定了主题的,所以状态栏颜色等都能自动马上生效,而且不需要通过代码修改状态栏颜色,因此这个bug是act的xml定义的主题和代码设置的主题冲突bug.

    关于This Activity already has an action bar supplie

     This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead.
                                                                                                            at androidx.appcompat.app.AppCompatDelegateImpl.setSupportActionBar(Ap
    

    如果在actionbar已经在xml中指定的情况(如果act没有指定则从application节点继承),在代码里面继续设置是会报错的,可在setContentView代码之前调用setTheme指定不包含actionbar的解除actionbar
    则调用setSupportActionBar不会抛出已设置的错误。
    setSupportActionBar的作用是把布局xml中的toolbar 依附到act中。

    关于状态栏通过setTheme recreate有些东西不生效 ,重启不生效的原因 最根本原因是使用了MaterialComponents 主题而不是Theme.AppCompat,但是不使用MaterialComponents主题会导致google的组件样式无法全局生效,这是个矛盾,而且导致我的app大量崩溃,都是因为google的组件问题。
    然后我继续找问题,还是改成了MaterialComponents主题,发现recreate又没有bug了,可以不重启全部更新。 之前又不行,我搞的精神崩溃了,也许是编译缓存问题??。。
    总之最后通过recreate可以实现当前界面更新状态栏,不过第二个界面则不行,需要代码设置。不过体验比之前好了,不需要彻底重启app,由于保存了状态,基本上切换主题就感觉没有重启act的感觉,实际上是重建了的。

    最后的最后我发现深色切换 回来或者切换过去,会导致很多地方不生效,比如状态栏,部分背景,
    在recreate执行之前重新设置一遍主题可以解决此问题

        if (which != currentMode) {
                                dialog.dismiss();
                                ThemeMode value = values[which];
                                NightModeUtils.getInstance(AppContext.getInstance()).setThemeMode(value);
                                if (currentMode == 0 || which == 0) {//如果是从深色切换过来的就需要先执行setTheme,也就是执行了2次。
                                    NightModeUtils.getInstance(getContext()).applySetting(getContext());
                                    getActivity().recreate();
                                } else {
                                    EventBus.getDefault().post(new ThemeChangeEvent().themeChange());
    
                                }
    
                            }
    

    最后的最后是这样的

     ThemeMode value = values[which];
                                NightModeUtils.getInstance(AppContext.getInstance()).setThemeMode(value);
                                if (currentMode == 0 || which == 0) {
                                    //call setTheme
                                    NightModeUtils.getInstance(getContext()).applySetting(getContext());
                                    //如果重启会发现部分没生效,深色模式的切换是不需要重启就能生效的
                                } else {
                                    getActivity().recreate();
                                }
    

    完整代码

    
    import android.app.Activity
    import android.content.Context
    import android.content.res.TypedArray
    import android.util.Log
    import androidx.appcompat.app.AppCompatActivity
    import androidx.appcompat.app.AppCompatDelegate
    import com.sotrun.app.R
    import com.sotrun.app.base.BaseActivity
    import com.sotrun.app.utils.DateUtils
    import java.io.Serializable
    import java.util.*
    
    open class NightModeUtils constructor(context: Context) {
    
        private val mSpf =
            context.applicationContext.getSharedPreferences(SP_THEME_NAME, Context.MODE_PRIVATE)
    
        companion object {
    
            @Volatile
            private var INSTANCE: NightModeUtils? = null
    
            fun getSpfThemeMode(context: Context): Int =
                context.getSharedPreferences(SP_THEME_NAME, Context.MODE_PRIVATE)
                    .getInt(SPF_THEME_MODE, ThemeMode.MODE_FOLLOW_SYSTEM.intValue)
    
            @JvmStatic
            fun getInstance(context: Context): NightModeUtils =
                INSTANCE ?: synchronized(this) {
                    INSTANCE ?: NightModeUtils(context).also {
                        INSTANCE = it
                    }
                }
    
            private const val SPF_THEME_MODE = "theme_mode"
            private const val SP_THEME_NAME = "config_data"
    
            private const val SPF_THEME_TIMER = "theme_timer"
        }
    
    
        /** 获取设置 */
        private fun getSpfThemeMode(): Int =
            mSpf.getInt(SPF_THEME_MODE, ThemeMode.MODE_FOLLOW_SYSTEM.intValue)
    
        /** 设置 */
        private fun setSpfThemeMode(mode: Int) {
            /*
            注意,当两个编辑器同时修改首选项时
    *时间,最后一个调用commit的人获胜。
    *
             */
            mSpf.edit().putInt(SPF_THEME_MODE, mode).commit()
        }
    
        /** 获取时间设置 */
        private fun getSpfThemeTimer(): String = mSpf.getString(SPF_THEME_TIMER, null) ?: "18:00~08:00"
    
        /** 设置时间 */
        private fun saveSpfThemeTimer(timer: String) {
            mSpf.edit().putString(SPF_THEME_TIMER, timer).apply()
        }
    
        /** 获取设置好的ThemeMode */
        fun getThemeMode(): ThemeMode = ThemeMode.parseOfInt(getSpfThemeMode())
    
        /** 设置模式 */
        fun setThemeMode(mode: ThemeMode) {
            setSpfThemeMode(mode.intValue)
        }
    
        /** 获取设置好的定时时间 */
        fun getThemeTime(): ThemeTime {
            val timeStr = getSpfThemeTimer()
            return ThemeTime(
                beginHour = timeStr.split("~")[0].split(":")[0].toInt(),
                beginMinute = timeStr.split("~")[0].split(":")[1].toInt(),
                endHour = timeStr.split("~")[1].split(":")[0].toInt(),
                endMinute = timeStr.split("~")[1].split(":")[1].toInt()
            )
        }
    
        /** 设置定时时间 */
        fun setThemeTime(time: ThemeTime) {
            saveSpfThemeTimer(time.toTimerString())
        }
    
        /**
         * 应用存储的设置
         */
        fun applySetting() {
            applySetting(null);
        }
    
        fun applySetting(context: Context?): Int {
            var themeId = 0;
            // 检查主题
            val themeModeInt = getSpfThemeMode()
            val themeMode = ThemeMode.parseOfInt(themeModeInt)
            var disableActionBar: Boolean = false;
            var actName: String = "";
            var needActionBar:Int =-1;
            if (context is BaseActivity) {
                needActionBar = context.needActionBar()
                if( needActionBar == 1) {
    
                    disableActionBar = false;
                }else if( needActionBar == 0) {
                    disableActionBar = true;
                }
            }
                actName =  context?.javaClass?.simpleName + " ,是否禁用actionBar " + disableActionBar;
            if (context is AppCompatActivity) {
                if (needActionBar==-1) {
                    var act: AppCompatActivity = context;
                    val a: TypedArray = act.obtainStyledAttributes(R.styleable.AppCompatTheme)
                    val needActionBar = a.getBoolean(R.styleable.AppCompatTheme_windowActionBar, false)
                    disableActionBar = !needActionBar
    
    //                disableActionBar = if(act.supportActionBar!=null) true else true;//act.supportActionBar is WindowDecorActionBar
                }
            }
            Log.w("ThemeStyle", "主题模式 ${themeMode.name} act $actName");
    
            if (themeMode == ThemeMode.BLUE_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Blue_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_Blue
                }
            } else if (themeMode == ThemeMode.YELLOW_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Yellow_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_Yellow
                }
            } else if (themeMode == ThemeMode.PURPLE_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_PURPLE_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_PURPLE
                }
            } else if (themeMode == ThemeMode.GREEN_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_GREEN_NoActionBar;
                } else {
                    themeId = R.style.Theme_MyApplication_GREEN
                }
            } else if (themeMode == ThemeMode.GREY_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Grey_NoActionBar;
                } else {
                    themeId = R.style.Theme_MyApplication_Grey
                }
            } else if (themeMode == ThemeMode.BROWN_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Brown_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_Brown
                }
            } else if (themeMode == ThemeMode.DEEP_ORANGE_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_DeepOrange_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_DeepOrange
                }
            } else if (themeMode == ThemeMode.AMBER_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Amber_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_Amber
                }
            } else if (themeMode == ThemeMode.CYAN_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_Cyan_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_Cyan
                }
            } else if (themeMode == ThemeMode.BLACK_THEME) {
                if (disableActionBar) {
                    themeId = R.style.Theme_MyApplication_BLACK_NoActionBar;
                } else {
                    themeId = R.style.Theme_MyApplication_BLACK;
                }
            } else {
                if (disableActionBar) {//如果appcontext设置actionbar,act manifest.xml没有声明解除actionbar,然后调用setSupportBar则会抛出异常,因此需要处理适配。
                    themeId = R.style.Theme_MyApplication_DefaultBlue_NoActionBar
                } else {
                    themeId = R.style.Theme_MyApplication_DefaultBlue
                }
            }
    
            if (themeId != 0) {
                if(context is Activity){
                context?.setTheme(themeId)
    
                }else{
    
    //                context?.theme?.applyStyle(themeId, true)
                }
    //            return themeId;
            }
            AppCompatDelegate.setDefaultNightMode(
                when (themeMode) {
                    ThemeMode.MODE_ALWAYS_ON -> AppCompatDelegate.MODE_NIGHT_YES
                    ThemeMode.MODE_ALWAYS_OFF -> AppCompatDelegate.MODE_NIGHT_NO
                    ThemeMode.MODE_FOLLOW_SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
                    else -> {
                        AppCompatDelegate.MODE_NIGHT_NO
                    }
                }
    
    
            )
            return themeId
    
        }
    
        /**
         * 定时开启
         */
        private fun clock(): Int {
            val time = getThemeTime()
            val startTime = time.startTime.replace(":", ".").toFloat()
            val stopTime = time.stopTime.replace(":", ".").toFloat()
            val curTime = DateUtils.getFormatDate("HH.mm", Date()).toFloat()
            return if (stopTime > startTime) {
                // 结束时间和开始时间都在同一天
                if (curTime > startTime && curTime < stopTime) {
                    AppCompatDelegate.MODE_NIGHT_YES
                } else {
                    AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
                }
            } else {
                // 结束时间在开始时间的后一天
                if (curTime > startTime || curTime < stopTime) {
                    AppCompatDelegate.MODE_NIGHT_YES
                } else {
                    AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
                }
            }
        }
    }
    
    /**
     * 主题设置时间
     */
    data class ThemeTime(
        // 开始小时
        val beginHour: Int,
        // 开始分钟
        val beginMinute: Int,
        // 结束小时
        val endHour: Int,
        // 结束分钟
        val endMinute: Int,
        // 开始时间
        var startTime: String = "00:00",
        // 结束时间
        var stopTime: String = "00:00"
    ) : Serializable {
    
        init {
            startTime = "${upTo2String(beginHour)}:${upTo2String(beginMinute)}"
            stopTime = "${upTo2String(endHour)}:${upTo2String(endMinute)}"
        }
    
        fun toTimerString(): String = "$startTime~$stopTime"
    
        // 保存成长度为2的字符串
        private fun upTo2String(value: Int): String {
            val valueStr = "$value"
            val sb = StringBuilder()
            if (valueStr.length < 2) {
                for (i in 0 until 2 - valueStr.length) {
                    sb.append("0")
                }
            }
            sb.append(valueStr)
            return sb.toString().substring(sb.length - 2)
        }
    }
    
    

    设置代码

      getBinding().rlMyThemeSetting.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                    int currentMode = NightModeUtils.Companion.getSpfThemeMode(AppContext.getInstance());
                    ThemeMode[] values = ThemeMode.values();
                    ThemeColorSelectAdapter.Bean[] items = new ThemeColorSelectAdapter.Bean[values.length];
                    for (int i = 0; i < values.length; i++) {
                        String title = AppContext.getInstance().getString(values[i].getStringValueId());
                        ThemeColorSelectAdapter.Bean bean = new ThemeColorSelectAdapter.Bean();
                        bean.title = title;
                        bean.color = values[i].getColor();
                        items[i] = bean;
                    }
                    ThemeColorSelectAdapter arrayAdapter = new ThemeColorSelectAdapter(
                            getActivity(), R.layout.view_color_check_item, items);
                    builder.setSingleChoiceItems(arrayAdapter, currentMode, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if (which != currentMode) {
                                dialog.dismiss();
                                ThemeMode value = values[which];
                                NightModeUtils.getInstance(AppContext.getInstance()).setThemeMode(value);
                                if (currentMode == 0 || which == 0) {
                                    //call setTheme
                                    NightModeUtils.getInstance(getContext()).applySetting(getContext());
                                    //如果重启会发现部分没生效,深色模式的切换是不需要重启就能生效的,如果不先调用切换模式代码,调用recreate也是没用的。
                                } else {//setTheme没用
                                    getActivity().recreate();
                                }
                                updateThemeStatusTextView();
    
                            }
    
                        }
    
                    });
                    builder.setTitle(AppContext.getStr(R.string.deep_color_theme_setting));
                    builder.show();
    
                }
            });
    
    

    thememode

    enum class ThemeMode(val intValue: Int, val stringValueId: Int,val color:Int) {
        MODE_ALWAYS_ON(0, R.string.theme_mode_darkmode,R.color.black_no_dark),
        MODE_ALWAYS_OFF(1, R.string.theme_mode_default_blue,R.color.themeColorNoDark),
        MODE_FOLLOW_SYSTEM(2, R.string.theme_mode_dark_follow_system,R.color.themeColorNoDark),
        BLUE_THEME(3, R.string.theme_blue,R.color.themeColorBlueNoDark),
        PURPLE_THEME(4, R.string.theme_purple,R.color.themeColorPurpleNoDark),
        GREEN_THEME(5, R.string.theme_green,R.color.themeColorGreenNoDark),
        YELLOW_THEME(6, R.string.yellow,R.color.themeColorYellowNoDark),
        BROWN_THEME(7, R.string.theme_brown,R.color.themeColorBrownNoDark),
        GREY_THEME(8, R.string.theme_grey,R.color.themeColorGreyNoDark),
        AMBER_THEME(9, R.string.theme_amber,R.color.themeColorAmberNoDark),
        CYAN_THEME(10, R.string.theme_cyan,R.color.themeColorCyanNoDark),
        DEEP_ORANGE_THEME(11, R.string.theme_deep_orange,R.color.themeColorDeepOrangeNoDark),
        BLACK_THEME(12, R.string.theme_black,R.color.black_no_dark);
    //    MODE_TIMER(30, R.string.theme_mode_3);
    
        companion object {
    
    
            @JvmStatic
            fun parseOfInt(intValue: Int) : ThemeMode {
                return when(intValue) {
                    MODE_ALWAYS_ON.intValue -> MODE_ALWAYS_ON
                    MODE_ALWAYS_OFF.intValue -> MODE_ALWAYS_OFF
                    MODE_FOLLOW_SYSTEM.intValue -> MODE_FOLLOW_SYSTEM
    //                MODE_TIMER.intValue -> MODE_TIMER
                    BLUE_THEME.intValue -> BLUE_THEME
                    YELLOW_THEME.intValue -> YELLOW_THEME
                    PURPLE_THEME.intValue -> PURPLE_THEME
                    GREEN_THEME.intValue -> GREEN_THEME
                    BROWN_THEME.intValue -> BROWN_THEME
                    GREY_THEME.intValue -> GREY_THEME
                    CYAN_THEME.intValue -> CYAN_THEME
                    AMBER_THEME.intValue -> AMBER_THEME
                    DEEP_ORANGE_THEME.intValue -> DEEP_ORANGE_THEME
                    BLACK_THEME.intValue -> BLACK_THEME
    //              BLACK_THEME.intValue,!in 0.. 30-> BLACK_THEME
                    else -> MODE_FOLLOW_SYSTEM
                }
            }
        }
    }
    

    配色参考
    http://mcg.mbitson.com/#!?mcgpalette0=%235768fe
    https://www.materialpalette.com/light-blue/blue-grey
    https://codecrafted.net/randommaterial

    相关文章

      网友评论

        本文标题:【官方推荐方式】【原创】安卓换肤踩坑纯色模式app使用attr轻

        本文链接:https://www.haomeiwen.com/subject/anwosrtx.html