实现夜间模式,不需要recreate,不闪屏
通过资源 id 映射,回调自定义 ThemeChangeListener
接口来处理日间/夜间模式的切换。
在values下面colors.xml里面
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <color name="colorPrimary">#3F51B5</color>
- <color name="colorPrimary_night">#3b3b3b</color>
- <color name="colorPrimaryDark">#303F9F</color>
- <color name="colorPrimaryDark_night">#383838</color>
- <color name="colorAccent">#FF4081</color>
- <color name="colorAccent_night">#a72b55</color>
- <color name="textColor">#FF000000</color>
- <color name="textColor_night">#FFFFFF</color>
- <color name="backgroundColor">#FFFFFF</color>
- <color name="backgroundColor_night">#3b3b3b</color>
- </resources>
- public class ThemeManager {
- // 默认是日间模式
- private static ThemeMode mThemeMode = ThemeMode.DAY;
- // 主题模式监听器
- private static List<OnThemeChangeListener> mThemeChangeListenerList = new LinkedList<>();
- // 夜间资源的缓存,key : 资源类型, 值<key:资源名称, value:int值>
- private static HashMap<String, HashMap<String, Integer>> sCachedNightResrouces = new HashMap<>();
- // 夜间模式资源的后缀,比如日件模式资源名为:R.color.activity_bg, 那么夜间模式就为 :R.color.activity_bg_night
- private static final String RESOURCE_SUFFIX = "_night";
- /**
- * 主题模式,分为日间模式和夜间模式
- */
- public enum ThemeMode {
- DAY, NIGHT
- }
- /**
- * 设置主题模式
- *
- * @param themeMode
- */
- public static void setThemeMode(ThemeMode themeMode) {
- if (mThemeMode != themeMode) {
- mThemeMode = themeMode;
- if (mThemeChangeListenerList.size() > 0) {
- for (OnThemeChangeListener listener : mThemeChangeListenerList) {
- listener.onThemeChanged();
- }
- }
- }
- }
- /**
- * 根据传入的日间模式的resId得到相应主题的resId,注意:必须是日间模式的resId
- *
- * @param dayResId 日间模式的resId
- * @return 相应主题的resId,若为日间模式,则得到dayResId;反之夜间模式得到nightResId
- */
- public static int getCurrentThemeRes(Context context, int dayResId) {
- if (getThemeMode() == ThemeMode.DAY) {
- return dayResId;
- }
- // 资源名
- String entryName = context.getResources().getResourceEntryName(dayResId);
- // 资源类型
- String typeName = context.getResources().getResourceTypeName(dayResId);
- HashMap<String, Integer> cachedRes = sCachedNightResrouces.get(typeName);
- // 先从缓存中去取,如果有直接返回该id
- if (cachedRes == null) {
- cachedRes = new HashMap<>();
- }
- Integer resId = cachedRes.get(entryName + RESOURCE_SUFFIX);
- if (resId != null && resId != 0) {
- return resId;
- } else {
- //如果缓存中没有再根据资源id去动态获取
- try {
- // 通过资源名,资源类型,包名得到资源int值
- int nightResId = context.getResources().getIdentifier(entryName + RESOURCE_SUFFIX, typeName, context.getPackageName());
- // 放入缓存中
- cachedRes.put(entryName + RESOURCE_SUFFIX, nightResId);
- sCachedNightResrouces.put(typeName, cachedRes);
- return nightResId;
- } catch (Resources.NotFoundException e) {
- e.printStackTrace();
- }
- }
- return 0;
- }
- /**
- * 注册ThemeChangeListener
- *
- * @param listener
- */
- public static void registerThemeChangeListener(OnThemeChangeListener listener) {
- if (!mThemeChangeListenerList.contains(listener)) {
- mThemeChangeListenerList.add(listener);
- }
- }
- /**
- * 反注册ThemeChangeListener
- *
- * @param listener
- */
- public static void unregisterThemeChangeListener(OnThemeChangeListener listener) {
- if (mThemeChangeListenerList.contains(listener)) {
- mThemeChangeListenerList.remove(listener);
- }
- }
- /**
- * 得到主题模式
- *
- * @return
- */
- public static ThemeMode getThemeMode() {
- return mThemeMode;
- }
- /**
- * 主题模式切换监听器
- */
- public interface OnThemeChangeListener {
- /**
- * 主题切换时回调
- */
- void onThemeChanged();
- }
- }
在MainActivity.java找到按钮的id和根布局的id
在 MainActivity 中实现了 OnThemeChangeListener
接口,这样就可以在主题改变的时候执行回调方法。然后在 initTheme()
中去重新设置 UI 的相关颜色属性值。还有别忘了要在 onDestroy()
中移除 ThemeChangeListener 。
- public class MainActivity extends AppCompatActivity implements ThemeManager.OnThemeChangeListener {
- private TextView tv;
- private Button btn_theme;
- private RelativeLayout relativeLayout;
- private ActionBar supportActionBar;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- ThemeManager.registerThemeChangeListener(this);
- supportActionBar = getSupportActionBar();
- btn_theme = (Button) findViewById(R.id.btn_theme);
- relativeLayout = (RelativeLayout) findViewById(R.id.relativeLayout);
- tv = (TextView) findViewById(R.id.tv);
- btn_theme.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- ThemeManager.setThemeMode(ThemeManager.getThemeMode() == ThemeManager.ThemeMode.DAY
- ? ThemeManager.ThemeMode.NIGHT : ThemeManager.ThemeMode.DAY);
- }
- });
- }
- public void initTheme() {
- tv.setTextColor(getResources().getColor(ThemeManager.getCurrentThemeRes(MainActivity.this, R.color.textColor)));
- btn_theme.setTextColor(getResources().getColor(ThemeManager.getCurrentThemeRes(MainActivity.this, R.color.textColor)));
- relativeLayout.setBackgroundColor(getResources().getColor(ThemeManager.getCurrentThemeRes(MainActivity.this, R.color.backgroundColor)));
- // 设置标题栏颜色
- if(supportActionBar != null){
- supportActionBar.setBackgroundDrawable(new ColorDrawable(getResources().getColor(ThemeManager.getCurrentThemeRes(MainActivity.this, R.color.colorPrimary))));
- }
- // 设置状态栏颜色
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- Window window = getWindow();
- window.setStatusBarColor(getResources().getColor(ThemeManager.getCurrentThemeRes(MainActivity.this, R.color.colorPrimary)));
- }
- }
- @Override
- public void onThemeChanged() {
- initTheme();
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- ThemeManager.unregisterThemeChangeListener(this);
- }
- }