Mobile development

Alex Zhukovich

Support multiple themes in an Android application


In this post we will talk about supporting multiple themes in Android application.

demo_two_themes

We will create demo application with 2 themes. User can choose of of this theme for whole application. Theme in our application will be change background color, status bar color,…

This image show different style tags and meaning for Android 5.+.
Firstly need to add dependency for build.grade file in our project.

dependencies {
    compile 'com.android.support:appcompat-v7:25.2.0'
}

For support changing background theme for Android version less 5 we can add own attribute called “backgroundColor” for it need to add file attrs.xml┬áto /res/values.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="backgroundColor" format="color"/>
</resources>

Next step is create different themes. For it we can use styles.xml or themes.xml files. In this case I used to steles.xml file.

<resources>
    <style name="AppTheme.Blue" parent="Theme.AppCompat">
        <item name="colorPrimary">@color/primaryColor_blue</item>
        <item name="colorPrimaryDark">@color/primaryColorDark_blue</item>
        <item name="colorAccent">@color/primaryAccent_blue</item>
        <item name="backgroundColor">@color/primaryColorDark_blue</item>
    </style>
    <style name="AppTheme.Red" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/primaryColor_red</item>
        <item name="colorPrimaryDark">@color/primaryColorDark_red</item>
        <item name="colorAccent">@color/primaryAccent_red</item>
        <item name="backgroundColor">@color/primaryColorDark_red</item>
    </style>
</resources>

After it need to add all colors to colors.xml file (/res/values/).

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="primaryColor_blue">#2196F3</color>
    <color name="primaryColorDark_blue">#1976D2</color>
    <color name="primaryAccent_blue">#E3F2FD</color>

    <color name="primaryColor_red">#F44336</color>
    <color name="primaryColorDark_red">#D32F2F</color>
    <color name="primaryAccent_red">#FFEBEE</color>
</resources>

Next step is update layout for MainActivity. In my case it’s a activity_main.xml (/res/layout/).

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="12dp"
    android:paddingLeft="8dp"
    android:paddingRight="8dp"
    android:background="?attr/backgroundColor">
    <Button
        android:id="@+id/blue_theme_btn"
        android:text="BLUE"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/red_theme_btn"
        android:text="RED"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

When we used tag android:background=”?attr/backgroundColor” it’s our own tag, which we created in attrs.xml file. This tag depends of theme which active right now.

Our theme must saved after close app. For we will use SharedPreferences. I created class called Utility.java which contain next code.

public class Utility {

    public static void setTheme(Context context, int theme) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        prefs.edit().putInt(context.getString(R.string.prefs_theme_key), theme).apply();
    }

    public static int getTheme(Context context) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        return prefs.getInt(context.getString(R.string.prefs_theme_key), -1);
    }
}

For correct work this class need to add string constant to strings.xml file (/res/values/).

<resources>
    <string name="app_name">MultipleThemesApp</string>

    <string name="prefs_theme_key">theme</string>
</resources>

We can check and update theme in our MainActivity, but better way is create BaseActivity, which will check and init our theme for activity.

public class BaseActivity extends AppCompatActivity {

    private final static int THEME_BLUE = 1;
    private final static int THEME_RED = 2;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        updateTheme();
    }
    public void updateTheme() {
        if (Utility.getTheme(getApplicationContext()) <= THEME_BLUE) {
            setTheme(R.style.AppTheme_Blue);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                getWindow().setStatusBarColor(getResources().getColor(R.color.primaryColorDark_blue));
            }
        } else if (Utility.getTheme(getApplicationContext()) == THEME_RED) {
            setTheme(R.style.AppTheme_Red);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                getWindow().setStatusBarColor(getResources().getColor(R.color.primaryColorDark_red));
            }
        }
    }
}

We must extend Main Activity from BaseActivity and add listeners to click button for change theme and recreate activity.

public class MainActivity extends BaseActivity implements View.OnClickListener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((Button)findViewById(R.id.blue_theme_btn)).setOnClickListener(this);
        ((Button)findViewById(R.id.red_theme_btn)).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.blue_theme_btn:
                Utility.setTheme(getApplicationContext(), 1);
                recreateActivity();
                break;
            case R.id.red_theme_btn:
                Utility.setTheme(getApplicationContext(), 2);
                recreateActivity();
                break;
        }
    }

    public void recreateActivity() {
        Intent intent = getIntent();
        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        finish();
        overridePendingTransition(0, 0);
        startActivity(intent);
        overridePendingTransition(0, 0);
    }
}

Last step is update AndroidManifest.xml with new default theme:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.alexzh.multiplethemesapp">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme.Blue" >
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Full source code you can find here.

« »

© 2018 Mobile development. Theme by Anders Norén.