Allows your Android app to use multiple themes (Part 2)

Source: Internet
Author: User

Allows your Android app to use multiple themes (Part 2)

 

In the first part of this post, we have created a light theme and made initial preparation to support multiple themes. in this blog post, we will continue that effort, creating another theme and allowing dynamic switching of themes during runtime.

In the previous blog, we created a bright style topic and made some preparations for using multiple themes. What about today, I plan to continue with the previous blog post in this blog post. The content I want to talk about today is about the following three parts: Enable Android applications to use multiple themes, create a dark-style topic and allow the Android app to switch between different topics at runtime.

Ideally, if we treat theme as a configuration, we shocould be able to specify theme-specific resources under a 'Theme-qualifier 'resources directory, e.g. values-dark for dark theme resources and values-light for light theme resources. unfortunately, this is not yet an option at the time of this post.

Ideally, if we regard theme settings as a configuration, we should be able to specify the desired theme in a directory similar to theme-qualifier, for example: values-dark is the gray style theme we want, while values-light is the bright style theme. But unfortunately, in the implementation method described in this blog, this method has not become one of the implementation methods.

So how shoshould we specify resources for multiple themes? If we look at how resources are organized in appcompat, we will have a rough idea of how the Android team organize their theme specific resources. Materialistic also employs a similar approach.

So how do we specify the corresponding resource files for different themes? If we know how appcompat uses resource files, we will have a rough understanding of how the Android system manages and uses resource files. There is no doubt that the method used in Materialistic is similar to that used in Android.

Theming topic settings

Values/styles. xml

 

Values/color. xml

...
  .........

Here we add a new dark theme called AppTheme. dark, and for style and color consistency, we extend from appcompat's theme Theme. appCompat (a dark theme ). unfortunately, since our two themes extend two different base themes, we cannot share any common attributes (the same way a class in Java cannot extend two or more classes ).

In the above operation, we created an AppTheme. in addition, to maintain the consistency between style and color, we AppTheme. the Dark topic is derived from the Theme of appcompat. appCompat topic (a gray-style topic that comes with Android ). However, because our two themes (bright style and dark style) are derived from different basic themes, attributes cannot be shared between them (in JAVA, class ).

The two themes shoshould have appropriate (different if applicable) values for base Android and appcompat theme attributes, e.g. android: textColorPrimary for dark theme shocould be light, and for light theme shocould be dark. by convention, here we suffix alternative theme colors with Inverse.

These two themes should have some appropriate attribute values that can be used to set basic Android and appcompat theme attributes at the same time. For example, in a dark style, android: textColorPrimary should be set to bright, in the bright style, android: textColorPrimary should be gloomy. According to the naming conventions, we will use the opposite suffix here to distinguish the alternative theme colors.

Tip

Try out your alternative theme by temporary switching android: theme for application in AndroidManifest. xml to see what extra colors/style you need to create. for certain cases a color may look okay in both dark and light theme.

Tips

In some cases, a color can be used in bright and gloomy theme at the same time. This is certainly a good news, but it cannot be implemented in most theme topics. So I want you to design the theme through the AndroidManifest. in xml, You can temporarily switch between the replaceable topics that are being used in your application to determine whether other colors/style files need to be added to your topic to meet your theme design needs.

Theme-specific resources

At this point, we shoshould have a pretty decent dark theme for our app, should t for some anomalies here and there, e.g. drawables used for action bar menu items. A dark action bar expects light-color menu items, and vice versa. in order to tell Android to use different drawables for different app themes, we create custom attributes that allow specifying reference to the correct drawable, and provide different drawable references as values for these custom attributes under different themes (the same way appcompat library provides provim attributes such as colorPrimary ).

Resource files of a specific topic

Now, I believe that we can easily design a gloomy style theme for our App, but there are still some minor troubles, such: the drawables resource file used to beautify the action bar menu options. The dimmed action bar needs to be decorated with bright colors for its menu options, and vice versa. To enable Android to differentiate different drawables resource files under different App themes, we have created a custom property reference that can specify the correct resource file, different drawable references are provided for different topics and their values are assigned to specific custom attributes. (Wenwan is like a wife, and the appcompat library carefully prepares custom attribute values similar to colorPrimary for us)

Values/attrs. xml
...
Values/styles. xml
 Menu/my_menu.xml 
 

Similar implementation can be used to specify most custom attributes you need for theme specific resource values. one hiccup to this approach is that attribute resolving in drawable resources seems to be broken before API 21. for example, if you have a drawable which is a layer-list of colors, their values must be fixed for API <21. see this commit from Google I/O 2014 app for a fix.

Similar implementations can also be used to specify resource values for most Custom Attributes Based on your actual theme design needs. However, this method has a problem: according to actual needs, the corresponding attribute values are parsed from the drawable resource file, and the method applied to the topic does not seem feasible in versions earlier than API 21. For example, if you have a layer-list that contains various drawable resource files of the color you need, in versions earlier than API 21, these color values should be fixed, rather than constantly changing during App running. This issue was raised at the Google I/O 2014 Conference and asked for corresponding solutions. (For more information, see Click Me !).

An alternative approach to avoid duplicating drawable resources for different themes is to use drawable tint. this attribute is available from API 21. dan Lew in his blog shows how to do this for all API levels. personally I wowould prefer to keep my Java implementation free of view logic if possible, so I choose to have different drawable resources per theme.

In addition, to avoid repeated use of the same resource file in different themes, we can use the tint attribute of drawable to solve this requirement. This attribute can be used in Versions later than API 21. But Dan Lew introduced us in his blog how to use the tint attribute in all API versions. But for my personal preferences, if I can, I would prefer to select a Java implementation that is not affected by the View logic, so I chose to provide different drawable resource files for each topic.

Dynamic theme switching

Now that we have two polished themes ready to be used, we need to allow users to choose which one they prefer and switch theme dynamically durtime. this can be done by having a SharedPreferences, says pref_dark_theme to store theme preference and use its value to decide which theme to apply. application of theme shoshould be done for all activies, before their views are created, so onCreate () is our only option to put the logic.

Dynamic topic Switching

Now we have two theme options available. Next we need to make it possible for users to switch between different theme based on their personal preferences when using the App. To implement this function, we can use SharedPreferences to store the selected topic by changing the value of pref_dark_theme and decide what topic our App will switch. However, considering the actual situation, after the topic is switched, the View of all activities of the App should be changed before being created. Therefore, we only need to implement our logic in the onCreate () method.

BaseActivity. java
public abstract class BaseActivity extends ActionBarActivity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         if (PreferenceManager.getDefaultSharedPreferences(this)
             .getBoolean(pref_dark_theme), false)) {
           setTheme(R.style.AppTheme_Dark);
        }
    super.onCreate(savedInstanceState);
    }
}

Here, since our app already has a default light theme, we only need to check if default preference has been overriden to override dark theme. the logic is put in the 'base' activity so it can be shared by all activities.

Here, because our App already uses the default bright style theme, we only need to check whether the default reference is reloaded and whether it is used to reload the gloomy style theme. In order that the default reference can be shared by all activities, the logic has been written in the "base" Activity.

Note that this approach will only apply theme for activities that are not in the back stack. for those that are already in current stack, they will still exhibit previous theme, as going back will only trigger onResume (). depends on product requirements, the implementation to handle these 'stamp' screens can be as simple as clearing the back stack, or restarting every single activity in the back stack upon preference change. here we simply clear back stack and restart current activity upon theme change.

It is worth noting that this method can only be used to change the theme of Acitivity that is not in the back stack. The activities that are already in the back stack will still be displayed as the previous topic, because when we end the current Activity and return to the previous Activity, only the onResume () method will be triggered, instead of the expected onCreate () method. Therefore, considering the actual functional design requirements of the product, we certainly need to solve these "obsolete" activities. Here I provide you with two solutions, both of which are quite simple: on the one hand, we can clear our back stack; on the other hand, once the preference is changed, we will re-load all Acitivty out of the stack in order in the back stack, change the theme of all the activities before re-entering the stack. Here for simplicity, we chose the implementation method: when the topic is changed, we simply clear the back stack and restart the current Activity.

SettingsFragment. java
public class SettingsFragment extends PreferenceFragment {
    ...

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
        @Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            if (!key.equals(pref_dark_theme)) {
                return;
            }

        getActivity().finish();

        final Intent intent = getActivity().getIntent();
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
        getActivity().startActivity(intent);
        }
    };
}

...

So that's it. Now we have an app with two polished themes for even the most picky users! Head over to hidroh/materialistic GitHub repository to checkout complete implementation!

Although it was a little abrupt, today's explanation is over. Now our App has two such elegant themes, and even the picky art is fresh, we will not abandon our App very low! If you want to know the specific implementation of the entire Materialistic or the source code of this function, you can get it from my GitHub ~


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.