【问题标题】:Change app theme globally programatically以编程方式全局更改应用主题
【发布时间】:2021-02-27 22:10:40
【问题描述】:

我正在编写一个应用程序,它具有此处声明的明暗模式:

styles.xml

<style name="Noon" parent="Theme.AppCompat.NoActionBar">
    <item name="upper_bg">@drawable/day_sky_top</item>
    <item name="lower_bg">@drawable/day_sky</item>
    <item name="android:statusBarColor">@color/colorPrimaryDark</item>
</style>

<style name="Night" parent="Theme.AppCompat.NoActionBar">
    <item name="upper_bg">@drawable/night_sky_top</item>
    <item name="lower_bg">@drawable/night_sky</item>
    <item name="android:statusBarColor">@color/colorNightDark</item>
</style>

通过关注this answer,我创建了以下文件:

/res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="customAttrs">
        <attr name="upper_bg" format="reference" />
        <attr name="lower_bg" format="reference" />
    </declare-styleable>
</resources>

并像这样自定义我的 ImageView:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/top_bg"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="0.65"
            android:src="?attr/upper_bg"/>

        <ImageView
            android:id="@+id/bottom_bg"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="0.35"
            android:src="?attr/lower_bg"/>
    </LinearLayout>

(注意这是代码的一部分,所有标签都已正确关闭。)

只要我有,一切都很好:

boolean night = true;
setTheme(night ? R.style.Night : R.style.Noon);
setContentView(R.layout.activity_main); // or whatever activity I'm in.

在我的应用的每一个 Activity 上。有没有办法一次运行此代码,以便我的主题在全局范围内更改?

【问题讨论】:

    标签: java android xml layout themes


    【解决方案1】:

    您仍然可以添加BaseActivity 来覆盖override fun onCreate(),将setTheme() 的责任委派给从它继承的任何其他Activity

    override fun onCreate(savedInstanceState: Bundle?) {
        val night = true
        setTheme(if (night) R.style.Night else R.style.Noon) 
    }
    

    如果你不喜欢BaseActivity,你可以根据用户的喜好在某处创建一个扩展函数来负责设置主题:

    fun Activity.setTheme() {
        val night = true
        // Or even have more than two theme styles
        this.setTheme(if (night) R.style.Night else R.style.Noon)
    }
    

    然后这样调用:

    override fun onCreate(savedInstanceState: Bundle?) {
        setTheme()
    }
    

    更新:Java 代码

    这个类将是每个必需的Activity 的基类

    public abstract class BaseActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            boolean night = true;
            setTheme(night ? R.style.Night : R.style.Noon);
        }
    }
    

    所以现在,假设您必须实现“功能 1”和“功能 2”,因此,您只需从 BaseActivity 继承它们。

    “功能 1”:

    public class Feature1Activity extends BaseActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState); // <- BaseActivity's onCreate() will set theme for you
            setContentView(R.layout.activity_feature_1);
        }
    }
    

    “功能 2”:

    public class Feature2Activity extends BaseActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState); // <- BaseActivity's onCreate() will set theme for you
            setContentView(R.layout.activity_feature_2);
        }
    }
    

    【讨论】:

    • 对不起,我不知道 Kotlin。你能把它翻译成Java吗?
    • @xvlaze,我已经添加了 Java 代码更新
    【解决方案2】:

    是的,你可以! 您必须使用 AppCompatDelegate 类的方法 setDefaultNightMode() 获取您要应用的主题的值,可用的值分别是 MODE_NIGHT_NO & MODE_NIGHT_YES & MODE_NIGHT_FOLLOW_SYSTEM 用于灯光、夜间和手机默认主题,您可以执行以下操作:

    AppCompatDelegate.setDefaultNightMode(THE_MODE_YOU_WANT);
    

    请务必注意,从 AppCompat v1.0.0 开始,当调用此方法时,它会重新创建所有正在运行的活动以应用主题。

    如果你运行的是 Api 29 或更高版本,你应该考虑使用 Force Dark,你可以在官方document 中查看它以更好地了解它。

    享受吧!

    【讨论】:

    • 但是定义为 R.style.mystyle 的自定义样式怎么样?
    • 你可以把夜间模式的主题文件放进去,当你把你的主题改成夜间模式时,android会自动读取它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    • 1970-01-01
    • 1970-01-01
    • 2017-09-19
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多