Android implements an in-depth understanding of day and night mode
In this article, three schemes for day / night mode switching are given. The combination of the three schemes may lead to a long length of the article. Please read patiently.
1. Use the settheme method to reset the theme of the activity;
2. Set uimode in Android support library to support day / night mode switching;
3. Through resource ID mapping, callback the custom themechangelistener interface to handle day / night mode switching.
1、 Using the settheme method
Let's take a look at the scheme of day / night mode switching using settheme method. The idea of this scheme is very simple. When the user selects the night mode, the activity is set as the theme of the night mode, and then let the activity call the recreate () method to recreate it.
Then do it, in colors Two sets of colors are defined in the XML to represent the theme colors of day and night respectively:
Then in styles Two groups of topics are defined in XML, that is, day topics and night topics:
The mainbackground attribute in the theme is our custom attribute, which is used to represent the background color:
The next step is to look at the layout activity_ main. xml:
In the Android: background attribute of < relativelayout >, we use "? Attr / mainbackground" to represent it, which means that the background color of relativelayout will refer to the value of the mainbackground attribute defined in the topic in advance. In this way, the color change of day / night mode switching is realized.
Finally, the code of mainactivity:
There are several points to note in mainactivity:
1. After calling the recreate () method, the activity's life cycle will call onsaveinstancestate (bundle outstate) to back up relevant data, and then onrestoreinstancestate (bundle savedinstancestate) will be called to restore relevant data. Therefore, we save the value of theme for use after the activity is recreated.
2, after we restore the theme value in the onCreate (Bundle savedInstanceState) method, the setTheme () method must be called before setContentView () method, otherwise it will not be able to see the effect.
3. The recreate () method is added in API 11, so in Android 2 Exceptions will be thrown when used in X.
After pasting the above code, let's take a look at the effect diagram of the implementation of the scheme:
2、 Using the uimode method in the Android support library
The method of using uimode is also very simple. We need to put colors XML is defined as day / night. Then different colors will be selected according to different modes xml 。 After the activity calls recreate (), the function of switching day / night mode is realized.
Having said so much, go straight to the code. Here are values / colors xml :
Except values / colors In addition to XML, we also create a values night / colors XML file, which is used to set the color of night mode. The name of < color > must be the same as values / colors Corresponding in XML:
In styles XML to reference us in colors Colors defined in XML:
activity_ main. The content of the XML layout is almost the same as that in the settheme () method above, so it will not be posted here. After that, it becomes very simple. First select a default mode in myapplication:
Note that there are four types of modes to choose from:
1、MODE_ NIGHT_ No: use light theme instead of night mode;
2、MODE_ NIGHT_ Yes: use dark theme and night mode;
3、MODE_ NIGHT_ Auto: automatically switch the light / dark theme according to the current time;
4、MODE_ NIGHT_ FOLLOW_ System (default option): set to follow the system, usually mode_ NIGHT_ NO
When the user clicks the button to switch day / night, reset the corresponding mode:
Let's take a look at the effect diagram of uimode scheme:
In terms of the first two methods, the configuration is relatively simple, and the final implementation effect is basically the same. But the disadvantage is that you need to call recreate () to make it effective. The re creation of an activity must involve the saving of some states. This adds some difficulty. So let's look at the third solution.
Callback interface through resource ID mapping
The idea of the third method is to dynamically obtain the mapping of resource ID according to the set topic, and then use the callback interface to let the UI set the relevant attribute values. Let's specify here: the suffix "_night" should be added to the naming of resources in night mode. For example, the background color of day mode is named color_ Background, then the background resource of the corresponding night mode should be named color_ background_ night 。 OK, here are the colors we need for our demo xml :
You can see that each color will have a corresponding "_night" to match it.
Seeing this, someone will ask why the corresponding "_night" should be set? How to set the day / night mode? Here's the answer from thememanager:
The code of thememanager above is basically annotated, so it's not difficult to understand it. The core is getcurrentthemeres method. Explain the logic of getcurrentthemeres here. Dayresid in the parameter is the resource ID of daytime mode. If the current topic is daytime mode, dayresid will be returned directly. On the contrary, if the current topic is in night mode, first get the resource name and resource type according to dayresid. For example, there is now a resource called r.color Colorprimary, then the resource name is colorprimary and the resource type is color. Then get the cache according to the resource type and resource name. If there is no cache, it is necessary to obtain resources dynamically. The method used here is
The name parameter is the resource name, but it should be noted that the resource name here should also be suffixed with "_night", which is above colors Name defined in XML; The deftype parameter is the type of the resource. For example, color, drawable, etc;
Defpackage is the package name of the resource file, that is, the package name of the current app.
With the above method, you can use r.color The colorprimary resource finds the corresponding r.color colorPrimary_ Night resources. Finally, add the found nighttime mode resources to the cache. In this way, you can read it directly from the cache instead of dynamically looking up the resource ID again.
The rest of the code in thememanager should be relatively simple. I believe everyone can understand it.
Now let's look at the code of mainactivity:
The onthemechangelistener interface is implemented in mainactivity, so that the callback method can be executed when the topic changes. Then reset the relevant color attribute values of the UI in inittheme(). Also, don't forget to remove themechangelistener from ondestroy().
Finally, let's take a look at the effect of the third method:
Some people may say that the effect is no different from that of the first two methods, but if you look carefully, you will find that the first two methods will have a short black screen at the moment of switching mode, while the third method does not. This is because the first two methods call recreate (). The third method does not need to recreate the activity and is implemented by callback.
Comparison of three methods
Here, according to the routine, it should be time to summarize. Let's make a simple comparison according to the three methods given above:
Settheme method: you can configure multiple sets of themes, which is easier to use. In addition to the day / night mode, there can be other colorful themes. However, you need to call recreate(), and a black screen will flash at the moment of switching;
Uimode method: the advantage is that it has been supported in the Android support library and is simple and standardized. However, it is also necessary to call recreate(), and the black screen flashes;
Dynamically obtain resource ID and callback interface: this method is more complex than the first two methods. In addition, in the callback method, you need to set the attribute value related to each UI. However, there is no need to call recreate (), and there is no black screen flashing.
summary
The above is the whole content of this article. I hope it can be helpful to Android developers.