In this post we will talk about supporting multiple themes in Android application.
We will create demo application with 2 themes. User can choose of of this theme for whole application. Theme in our application will change background color, status bar color, etc.
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 styles.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 MainActivity
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.