0%

Android-动态切换主题

前言

对于资讯阅读类app的来说,夜间模式是必不可少的。本文提供一种不重启Activity实现动态切换主题的方案。

思路分析

基于接口回调机制,每个基类(BaseActivity)都实现同一个接口 ThemeChangeCallback

1
2
3
interface ThemeChangeCallback {
void onChangeTheme();
}

用一个列表保存ThemeChangeCallback

1
private static List<ThemeChangeCallback> sCallbacks = new ArrayList<ThemeChangeCallback>();

当改变主题时,对每个ThemeChangeCallback调用onChangeTheme,然后在BaseActivity的onChangeTheme方法中实现背景或者资源的切换即可.

1
2
3
4
5
public static synchronized void changeTheme() {
for (ThemeChangeCallback callback : sCallbacks)
if (callback != null)
callback.onChangeTheme();
}

实现

BaseActitivy.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class BaseActivity extends AppCompatActivity implements ThemeUtils.ThemeChangeCallback {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeUtils.addCallback(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ThemeUtils.removeCallback(this);
}
@Override
public void onChangeTheme() {
Drawable drawable = null;
if (ThemeUtils.getCurrentThemeId() == ThemeUtils.DAY_THEME_ID) {
drawable = getResources().getDrawable(R.color.colorPrimary);
} else if (ThemeUtils.getCurrentThemeId() == ThemeUtils.NIGHT_THEME_ID) {
drawable = getResources().getDrawable(R.color.colorAccent);
}
if (getWindow() != null) {
getWindow().setBackgroundDrawable(drawable);
}
if (getSupportActionBar() != null) {
getSupportActionBar().setBackgroundDrawable(drawable);
}
}
}

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.btn_change_bg);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ThemeUtils.changeTheme();
}
});
}
}

ThemeUtils.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class ThemeUtils {
private static List<ThemeChangeCallback> sCallbacks = new ArrayList<ThemeChangeCallback>();
private static int sCurrentThemeId = 0 ;
public static int DAY_THEME_ID = 0 ;
public static int NIGHT_THEME_ID = 1 ;
private ThemeUtils() {}
public static void addCallback(ThemeChangeCallback callback) {
if (callback != null) {
sCallbacks.add(callback);
}
}
public static void removeCallback(ThemeChangeCallback callback) {
if (callback != null) {
sCallbacks.remove(callback);
}
}
public static synchronized void changeTheme() {
sCurrentThemeId = sCurrentThemeId == DAY_THEME_ID ? NIGHT_THEME_ID : DAY_THEME_ID;
for (ThemeChangeCallback callback : sCallbacks)
if (callback != null)
callback.onChangeTheme();
}
public static int getCurrentThemeId() {
return sCurrentThemeId;
}
interface ThemeChangeCallback {
void onChangeTheme();
}
}

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.netease.changetheme.MainActivity">
<Button
android:id="@+id/btn_change_bg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="change bg"
android:layout_centerInParent="true"/>
</RelativeLayout>

效果

图1

缺陷

改变背景色时,沉浸式状态栏没有相应改变,有待优化。