Through resource id mapping, callback to customize ThemeChangeListener interface to handle day / night mode switching.
Under values, in colors.xml
Need a theme management class ThemeManager<?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>
In activity main.xml, you only need to write a button, and then give the root layout an ID (because you need to change the background color of the root layout)public class ThemeManager { // Default is day mode private static ThemeMode mThemeMode = ThemeMode.DAY; // Theme mode listener private static List<OnThemeChangeListener> mThemeChangeListenerList = new LinkedList<>(); // Nighttime resource cache, key: resource type, value < key: resource name, value:int value > private static HashMap<String, HashMap<String, Integer>> sCachedNightResrouces = new HashMap<>(); // Suffix of nighttime mode resource. For example, if the name of the Japanese mode resource is r.color.activity, then the nighttime mode is r.color.activity private static final String RESOURCE_SUFFIX = "_night"; /** * Theme mode, divided into day mode and night mode */ public enum ThemeMode { DAY, NIGHT } /** * Set theme mode * * @param themeMode */ public static void setThemeMode(ThemeMode themeMode) { if (mThemeMode != themeMode) { mThemeMode = themeMode; if (mThemeChangeListenerList.size() > 0) { for (OnThemeChangeListener listener : mThemeChangeListenerList) { listener.onThemeChanged(); } } } } /** * According to the resId of the incoming daytime mode, get the resId of the corresponding topic. Note: it must be the resId of the daytime mode * * @param dayResId resId of day mode * @return The resId of the corresponding topic. If it is in daytime mode, it will get dayResId; otherwise, nightResId will get nightResId */ public static int getCurrentThemeRes(Context context, int dayResId) { if (getThemeMode() == ThemeMode.DAY) { return dayResId; } // Resource name String entryName = context.getResources().getResourceEntryName(dayResId); // Resource type String typeName = context.getResources().getResourceTypeName(dayResId); HashMap<String, Integer> cachedRes = sCachedNightResrouces.get(typeName); // Fetch from the cache first, and return the id directly if any if (cachedRes == null) { cachedRes = new HashMap<>(); } Integer resId = cachedRes.get(entryName + RESOURCE_SUFFIX); if (resId != null && resId != 0) { return resId; } else { //If there is no dynamic acquisition based on resource id in the cache try { // Get resource int value through resource name, resource type and package name int nightResId = context.getResources().getIdentifier(entryName + RESOURCE_SUFFIX, typeName, context.getPackageName()); // Put in cache cachedRes.put(entryName + RESOURCE_SUFFIX, nightResId); sCachedNightResrouces.put(typeName, cachedRes); return nightResId; } catch (Resources.NotFoundException e) { e.printStackTrace(); } } return 0; } /** * Register ThemeChangeListener * * @param listener */ public static void registerThemeChangeListener(OnThemeChangeListener listener) { if (!mThemeChangeListenerList.contains(listener)) { mThemeChangeListenerList.add(listener); } } /** * Unregister ThemeChangeListener * * @param listener */ public static void unregisterThemeChangeListener(OnThemeChangeListener listener) { if (mThemeChangeListenerList.contains(listener)) { mThemeChangeListenerList.remove(listener); } } /** * Get theme pattern * * @return */ public static ThemeMode getThemeMode() { return mThemeMode; } /** * Topic mode switching listener */ public interface OnThemeChangeListener { /** * Callback on topic switching */ void onThemeChanged(); } }
Find the id of the button and the id of the root layout in MainActivity.java
The OnThemeChangeListener interface is implemented in MainActivity, so that the callback method can be executed when the theme changes. Then reset it in initTheme()
The value of the relevant color property of the UI. And don't forget to remove it in 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))); // Set title block color if(supportActionBar != null){ supportActionBar.setBackgroundDrawable(new ColorDrawable(getResources().getColor(ThemeManager.getCurrentThemeRes(MainActivity.this, R.color.colorPrimary)))); } // Set status bar color 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); } }