Android Theme switch (Theme) for day/night functionality

Source: Internet
Author: User

Objective

With the continuous improvement of the application function of an app, the increasing number of user groups, the update of the app is not only limited to functional requirements, how to do a good user experience, so that users spread a good experience of word-of-mouth, it is particularly important, and the user experience a day and night mode has become standard. In fact, day and night function is a kind of skin change, the realization of the function of the skin, but also divergent opinions, the total is divided into two categories: Theme Skin (Theme) and plug-in skin (apk skin).

插件换肤The principle of plug-in skin replacement is the main apk according to the current environment needs, resolve the corresponding plugin apk in the specified directory, get the resource file with the same name and dynamically replace it in the main APK application. Plug-in APK does not need to be installed, only need to be placed in the specified directory.

    • Advantages: can achieve a variety of theme-style loading, more flexible, need to add a new theme as long as a new plug-in APK, and configure the relevant resources, placed in the specified file directory on the line, very convenient.
    • Cons: You need to adapt the control to modify, to achieve the skin-changing function, for the custom control, you also need to spend a bit of time on the adaptation. and the plug-in apk that is placed in the folder may also cause the resource to be lost due to accidental deletion or corruption, which causes the skin to fail.

主题换肤The principle of theme skin rejuvenation is to configure multiple sets of themes in the main apk, each set of topics to use the appropriate resources for the same attribute.

    • Pros: Easier to understand than plug-in peels.
    • Cons: Adding a new theme style must be a new release. All the resource files are placed in the APK, the APK will appear very bloated, especially the picture resources, so the personal recommendation of a solid color line icon, and through coloring to achieve different themes under the possibility of skin changes.

Because today's theme is day and night mode, considering that there is no possibility of adding theme styles, the tradeoff is to use theme skinning to achieve day and night patterns, old routines, preview of effects (with the entrance of HD address attached)



To prepare related property styles and themes: Custom attr properties:

Theme skin change and plug-in principle is the same, is to control the loading of the corresponding resource files in different modes, just the way to achieve different. In the past, when we were writing XML layout files, the default property assignment was absolute, Android:background="#FFFFFF" or android:background="@color/white" .
And once the property is assigned this way, the default resource load is limited, and if there is a need for the view to be loaded in accordance with the current environment to configure specific resources, it can only be modified in the Java program code, the complexity is conceivable. So is there a way to make the assignment of an XML property dynamically load the default resource based on the changes in the current theme style?
Yes, that's today's wrist: custom attributes. In my view, the role of the custom attribute as a placeholder in theme skinning tells the system that this is a relative reference, and that the real resource reference is the assignment of the custom attribute in the list of topic style attributes for the current context.

1. In the Res-value directory, create a new resource file for the Attr property, for example: custom_theme_attrs.xml .
2. custom_theme_attrs.xml Create a new custom attribute in the file.

Format:

<?xml version="1.0" encoding="utf-8"?><resources>    <attr name="自定义属性名称" format="资源引用格式(color、dimen、reference...)" /></resources>

Example:

  <?xml version= "1.0" encoding= "Utf-8"?><resources> <!--control app background color format: color value, resource reference--< ; attr name= "Custom_attr_app_bg" format= "Color|reference"/> <!--control app title bar background color format: color value, resource reference--<attr N    Ame= "CUSTOM_ATTR_APP_TITLE_LAYOUT_BG" format= "Color|reference"/> <!--user avatar Display placeholder drawable format: color value, resource reference-- <attr name= "Custom_attr_user_photo_place_holder" format= "Color|reference"/> <!--user Nickname font color format: color value, resource reference- -<attr name= "Custom_attr_nickname_text_color" format= "Color|reference"/> <!--user Notes font Color format: color value, resource citation --<attr name= "Custom_attr_remark_text_color" format= "Color|reference"/> <!--the transparency of the user Picture display format: dimension value, Resource references--<attr name= "Custom_attr_user_photo_alpha" format= "Dimension|reference"/></resources> 

A friend who has written a custom view must be a stranger, not a custom attribute. The difference is that these attribute values are not wrapped in styleable , as for why I do not swim, the need for friends can understand the book author Chuyun South wrote "in-depth understanding of Android custom attr Style styleable and its application", feeling written good, thanks to share!!

Custom Theme Themes:

Style must not be unfamiliar, when it is necessary to write a lot of similar code blocks, we usually extract the common parts, configuration in the style, directly in the XML of the style attribute referenced, is very convenient. The theme here is actually one of the style styles, except that it is not confined to the assignment of the control style property, but often involves the window's correlation, which is a collection of style attributes. Now that you switch the app UI style by toggling the theme, you need to prepare multiple sets of theme styles when defining style theme styles.

1. In the Res-value directory, create a new Style property resource file, for example: custom_theme_styles.xml .
2. custom_theme_styles.xml Create a new custom theme in the file and assign a value to the specific system and custom attributes.

Format:

<?xml version="1.0" encoding="utf-8"?><resources>    <style name="自定义主题样式的名称" parent="继承的主题,可以是自定义主题样式也可以是系统主题样式">        <item name="属性名称">赋值的对应资源</item>    </style></resources>

Example:

  <?xml version= "1.0" encoding= "Utf-8"?><resources> <style name= "Mariotheme" parent= " Theme.AppCompat.Light.DarkActionBar "> <!--Hide Activity window actionbar--<item name=" windowactionb Ar >false</item> <!--hide the title bar of the Activity window--<item name= "Windownotitle" >true</ite m> </style> <style name= "Mariotheme.day" > <!--Daytime mode "CUSTOM_ATTR_APP_BG" is assigned #ffffff--&G        T <item name= "CUSTOM_ATTR_APP_BG" > #FFFFFF </item> ... </style> <style name= "Mariotheme.nigh T "> <!--" Custom_attr_app_bg "assignment in night mode is #1f1f1f---<item name=" CUSTOM_ATTR_APP_BG "> #1F1F1F & Lt;/item>. </style></resources>  

As shown in the example above, the first is to create a new custom theme that inherits from the system style, which is the base Theme.AppCompat.Light.DarkActionBar MarioTheme Base theme of a topic, where you can assign values to some common properties, such as some global window styles, Of course, these assigned attributes are also covered by a subclass topic that can be inherited later.
It then creates two new themes that inherit from the base theme MarioTheme.Day MarioTheme.Night , as well as day and night topics, and assigns custom attributes to the two themes respectively custom_attr_app_bg .

In fact, through the above two steps: [Custom properties –> custom theme, and in the theme of the custom properties assigned to the corresponding], the theme of the preparation of skin can be said to be completed. However, there are many areas that can be optimized for higher maintainability of the project, such as the #1F1F1F color values appearing directly in the style. This is a way that I am very opposed to, in the use of theme skin-changing applications, with the powerful application features, the number of custom attributes will be more and more, and I think the finer the custom attribute definition is better, so there must be a large number of attribute list to be maintained. It is also possible that most of them can be reused, why not organize them into a unified file, if the demand changes, resource references need to be modified, not to change the global search, why give yourself so much unnecessary workload! So I'm going to talk about custom properties.



Custom Resource resources:

The same type of resources in the corresponding directory, the size of resources defined in the values-dimens directory, the color resource definition in the directory values-colors , drawable resources defined in the values directory under the corresponding drawable directory ... And each resource should be configured with multiple sets based on different theme styles.

Custom color:

1. In the Res-value directory, create a new Color property resource file, for example: custom_theme_colors.xml .
2. custom_theme_colors.xml Create a new custom color color in the file.

Format:

<?xml version="1.0" encoding="utf-8"?><resources>    <color name="自定义color名称_day">对应的日间颜色值</color>    <color name="自定义color名称_night">对应的夜间颜色值</color></resources>

Define the app background color as an example:

<?xml version="1.0" encoding="utf-8"?><resources>    <!-- 日间模式下app背景色 -->    <color name="custom_color_app_bg_day">#FFFFFF</color>    <!-- 日间模式下app标题栏背景色 -->    <color name="custom_color_app_title_layout_bg_day">#FF2F3A4C</color>            <!-- 夜间模式下app背景色 -->    <color name="custom_color_app_bg_night">#1F1F1F</color>    <!-- 夜间模式下app标题栏背景色 -->      <color name="custom_color_app_title_layout_bg_night">#FF1D1D1D</color>     ... </resources>

Custom drawable:

1. Create a new folder in the Res directory drawable .
1. res-drawable Create a new drawable resource file under the directory.

Defines the placeholder drawable for a circular picture, example:

custom_drawable_user_photo_place_holder_day.xml

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android">    <solid android:color="@color/custom_color_user_photo_place_holder_bg_day" />    <corners android:radius="32dp" /></shape>

custom_drawable_user_photo_place_holder_night.xml

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android">    <solid android:color="@color/custom_color_user_photo_place_holder_bg_night" />    <corners android:radius="32dp" /></shape>

The recommended color values used in custom drawable are also consolidated into the custom_theme_colors.xml file.

<!-- 用户头像占位drawable背景颜色 --><color name="custom_color_user_photo_place_holder_bg_day">#29303B</color><color name="custom_color_user_photo_place_holder_bg_night">#171717</color>

Custom Colorstatelist:

As with selectordrawable, color can also set the selector selector.
Create a new file in the 1.value directory color.xml .
2. res-color.xml Create a new color resource file under the directory.

Example:

custom_selector_text_day.xml

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">    <item android:color="@color/custom_color_text_pressed_day" android:state_pressed="true" />    <item android:color="@color/custom_color_text_day" /></selector>

custom_selector_text_night.xml

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">    <item android:color="@color/custom_color_text_pressed_night" android:state_pressed="true" />    <item android:color="@color/custom_color_text_night" /></selector>

Similarly, the recommended color values used in custom colorstatelist are also consolidated into the custom_theme_colors.xml file.

Assign a value to a custom property under a different theme style:

Example:

  <?xml version= "1.0" encoding= "Utf-8"?><resources>//day-related attribute set <style name= "Mariotheme.day" > <item name= "custom_attr_app_bg" > @color/custom_color_app_bg_day</item> <item name= "Custom _ATTR_APP_TITLE_LAYOUT_BG "> @color/custom_color_app_title_layout_bg_day</item> <item name=" Custom_ Attr_user_photo_place_holder "> @drawable/custom_drawable_user_photo_place_holder_day</item> </style >//night Related property set <style name= "Mariotheme.night" > <item name= "custom_attr_app_bg" > @color/custom_co lor_app_bg_night</item> <item name= "CUSTOM_ATTR_APP_TITLE_LAYOUT_BG" > @color/custom_color_app_title_ layout_bg_night</item> <item name= "Custom_attr_user_photo_place_holder" > @drawable/custom_drawable_ User_photo_place_holder_night</item> </style></resources>  

The preparatory work is completed here. Because in the day and night mode switch is not very likely to involve the string, the size of the resource style changes, the implementation of the same way, so do not do too much to repeat, the need for friends can be customized to try.




To use a custom attribute in an XML layout file:

As long as the preparatory work is done well, it is very simple to use, that is, when the property is assigned to no longer use absolute resource references, but to reference the completed assignment of the custom properties:

That way, if the context context of the view control that sets the custom property sets the corresponding theme theme style, and the corresponding assignment is made to our custom style, the use of the style will work, and it is important to remember that the properties used in the project must be assigned under the theme style used. Otherwise the application will run with an error. Of course, for a better development experience, we can set the corresponding theme in preview mode to preview whether the style effect is effective, how does it work?

Demo Part layout code show, Example:

<?xml version= "1.0" encoding= "Utf-8"? ><linearlayout xmlns:android= "/http Caibaoyule.cnschemas.android.com/apk/res/android "xmlns:tools=" Http://schemas.android.com/tools "Android: Background= "? Attr/custom_attr_app_bg" android:layout_height= "match_parent" android:layout_width= "Match_parent" an droid:orientation= "vertical" > <view android:background= "? Attr/custom_attr_app_title_layout_bg" Android Oid:id= "@id/custom_id_title_status_bar" android:layout_width= "match_parent" android:layout_height= "0DP"/&gt    ; <relativelayout android:background= "? Attr/custom_attr_app_title_layout_bg" android:id= "@id/custom_id_titl E_layout "android:layout_width=" match_parent "android:layout_height=" 136DP "android:paddingbottom=" 16 DP "android:paddingright=" 12DP "android:paddingleft=" 12DP "android:paddingtop=" 8DP "> <i Mageview android:padding= "3DP" Android:layout_wIdth= "72DP" android:layout_height= "72DP" android:id= "@+id/theme_user_phjiadayule.cnoto" a Ndroid:layout_alignparentleft= "true" android:layout_alignparentbottom= "true" android:alpha= "? Attr/cu             Stom_attr_user_photo_alpha "tools:src="? Attr/custom_attr_user_photo_place_holder "/> <LinearLayout            android:layout_torightof= "@+id/theme_user_photo" android:layout_aligntop= "@+id/theme_user_photo" Android:layout_width= "Wrap_content" android:gravity= "center_vertical" Android:layout_margin                 left= "12DP" android:orientation= "vertical" android:layout_height= "72DP" > <textview Android:textcolor= "? Attr/custom_attr_nickname_text_color" android:layout_height= "Wrap_conte NT "android:layout_width=" Wrap_content "android:id=" @+id/theme_nickname "Android oid:text= "@string/nicknaMe "android:textsize=" 19DP "/> <textview android:textcolor="? attr/custom_at                Tr_remark_text_color "android:text=" @string/remark "android:layout_height=" Wrap_content " Android:layout_width= "Wrap_content" android:layout_margintop= "3DP" android:id= "@ +id/theme_remark "android:textsize=" 12WANJHYL.CNDP "/> </LinearLayout> </relativelayo Ut></linearlayout>

The two themes in the preview and the MarioTheme.Day.Preview MarioTheme.Night.Preview sum of each inheritance are MarioTheme.Day MarioTheme.Night not used in the project, and are primarily used to control the color of the status bar, a preview of the status bar immersion effect for the individual editor.

In this step, setTheme() you can load the view of the subject using the activity!! Is there a great?
One thing to note is that the setTheme() method must be called before the system calls the setContentView() method, and the individual recommendation is uniformly written to the base class Baseactivity onCreate() method. And what we need to do is to configure a tag control baseactivity to set different themes on the local sharepreference!
You may have been tempted to see it here, or you've already written it down one step at a stroke, but the app ran and found that clicking on the button call method in the activity setTheme() doesn't change the activity, or it doesn't change back to the last activity. It setTheme() 's not that the method doesn't work, and the setTheme() method does have the effect (you can call the Gettheme () method to see if the current theme has changed). What's the reason? That's because these views are already loaded, and setting the theme doesn't trigger the system to refresh the UI, so we need to trigger it manually.

I recommend two kinds of UI refreshes after changing the theme:

    • 重新创建ActivityOn the re-creation of activity, only need to invoke the activity of the recreate() method on the line, the ordinary non-complex UI, with this method can basically meet, which mainly related to onSaveInstanceState() the application of the state of the Save, The use of this method to recreate the activity is also the official Google more respected, interested to know.
    • 手动加载当前主题下的应用资源That's what I need to focus on here. Because of the complexity and specificity of the UI, not all application activity can be saved by the onSaveInstanceState(kkucai.cn) current application state, so it is important to know how to get the required property resources from the current topic.

Get the resource specified by the current theme custom property:

In fact, access to this resource is also very simple, but also two steps:

    • Step-01 获取TypedValue

      TypedValue typedValue = new TypedValue(jiiyuan.cn); Resources.Theme theme = getTheme(); try {    theme.resolveAttribute(R.attr.自定义属性, typedValue, true);} catch (Exception e) {    e.printStackTrace();}

First, define a typedvalue to host the resource resource property, then get the theme topic corresponding to the current context, resolveAttribute() and then obtain the resource information for the given property ID under the current topic and assign a value to the defined Typedvalue. Because there may be exceptions thrown by the resource information for a given property, it is recommended to Try&catch to catch possible exceptions

    • Step-02 根据获取的TypedValue所包含的资源信息获取对应的资源

      Resources resources = getResources();    try {        int color = ResourcesCompat.getColor(resources, typedValue.resourceId, null); // 获取颜色值        Drawable drawable = ResourcesCompat.getDrawable(resources, typedValue.resourceId, null); // 获取Drawable对象        String string = resources.getString(typedValue.resourceId); // 获取字符串    } catch (Exception e) {        e.printStackTrace();    }

One of the most important attributes of Typedvalue is resourceId to make sure that the obtained typedvalue is not null. We can typedValue.resourceId get the ID of the resource, just like to know the ID of a color resource is R.color.black , let you go to get the color value, know a drawable resource ID is R.drawable.ic_luncher , let you go to get drawable object, think about simple (cover face. jpg). It is important to note that in order to avoid the exception of resource acquisition failure when obtaining the corresponding resource, various methods of obtaining resources are recommended to wrap with Try&catch. In the case of resource acquisition, there is an auxiliary class in the demo at the end of this paper, which makes a MarioResourceHelper small package for the resource acquisition and is more convenient to use.

The next thing to do is to replace the specific resources.

Add one point:

As to the previous article on the theme of the skin defects, one of them is that all the resource files need to be placed in the main apk file packaging and publishing, perhaps different themes will have multiple sets of picture resources, in the context of Android limited memory, this is a very bad situation.
And in the previous article, I also mentioned that to deal with this phenomenon, we can do is to use drawable coloring, try to use a set of picture resources to achieve a variety of topics. Remember! Shaded images require a solid-colored, background-transparent PNG, because coloring does not differentiate between colors, but instead colors the specified color on all opaque areas uniformly. coloring details Do not repeat, the online "drawable coloring of the back compatibility," a detailed description of the article, thank the author to share!! And what we're going to do is to define the color values that need to be colored on different topics, get the corresponding color values for different topics, and shade specific drawable. The MarioResourceHelper helper class also encapsulates the drawable coloring method.

? GitHub Project Source address?

Android Theme switch (Theme) for day/night functionality

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.