以编程方式全局更改应用程序主题
Change app theme globally programatically
我正在编写一个具有明暗模式的应用程序,如此处声明:
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>
并像这样自定义我的 ImageViews:
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 上。 有没有办法 运行 此代码一次,以便我的主题在全球范围内改变?
您仍然可以添加 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代码
这 class 将是您的基础 class 每个必需的 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);
}
}
是的,你可以!
您必须使用 class AppCompatDelegate 的方法 setDefaultNightMode() 获取您要应用的主题的值,可用的值是 MODE_NIGHT_NO & MODE_NIGHT_YES & MODE_NIGHT_FOLLOW_SYSTEM for light , night 和 phone 分别是默认主题,你可以这样做:
AppCompatDelegate.setDefaultNightMode(THE_MODE_YOU_WANT);
重要的是要注意,从 AppCompat v1.0.0 开始,当调用此方法时,它会重新创建所有 运行 activity 以应用主题。
如果你运行 Api29以上,你应该考虑使用Force Dark,你可以在官方document中查看所有内容以更好地了解它。
尽情享受吧!
我正在编写一个具有明暗模式的应用程序,如此处声明:
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>
并像这样自定义我的 ImageViews:
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 上。 有没有办法 运行 此代码一次,以便我的主题在全球范围内改变?
您仍然可以添加 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代码
这 class 将是您的基础 class 每个必需的 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);
}
}
是的,你可以! 您必须使用 class AppCompatDelegate 的方法 setDefaultNightMode() 获取您要应用的主题的值,可用的值是 MODE_NIGHT_NO & MODE_NIGHT_YES & MODE_NIGHT_FOLLOW_SYSTEM for light , night 和 phone 分别是默认主题,你可以这样做:
AppCompatDelegate.setDefaultNightMode(THE_MODE_YOU_WANT);
重要的是要注意,从 AppCompat v1.0.0 开始,当调用此方法时,它会重新创建所有 运行 activity 以应用主题。
如果你运行 Api29以上,你应该考虑使用Force Dark,你可以在官方document中查看所有内容以更好地了解它。
尽情享受吧!