Reputation: 183
I'm trying to implement theme switching on my application, and I can't seem to refresh an activity and set them theme without having to restart the whole activity (a.k.a finish() + startActivity()).
I tried invalidating findViewById(android.R.id.content) but it wont refresh the activity. Changing orientations change the theme given that onCreate is called once again.
So how do apps like TweetLanes implement this feature without having to restart the application/activity?
Thanks
Upvotes: 2
Views: 7816
Reputation: 116
Fairly simple.
Let's say you have a resource file called /res/values/app_themes.xml
. In this xml file you can define your app style. Let's call it appGeneralTheme
, it should look more or less like this:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="appGeneralTheme">
<!- Ofc you would use meaningful names and a separate file for colours but it's not the point. Those could be even different drawables, different strings, any kind of value can be styled/themed-->
<item name="foo">#FF0000</item>
<item name="bar">#00FF00</item>
<item name="baz">#0000FF</item>
</style>
</resources>
Now let's define those particular themes that the user will be able to change. We can do it in few ways:
app_themes.xml
filepickables_themes.xml
qux_theme.xml, quux_theme.xml
etcFor the simplicity sake let's keep all in one place, so in our app_themes.xml
we will add modified themes:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="appGeneralTheme">
<item name="foo">#FF0000</item>
<item name="bar">#00FF00</item>
<item name="baz">#0000FF</item>
<!-- other items -->
</style>
<style name="quxTheme" parent="@style/appGeneralTheme">
<item name="foo">#FF00FF</item>
<item name="bar">#00FFFF</item>
<item name="baz">#FFFF00</item>
</style>
<style name="quuxTheme" parent="@style/appGeneralTheme">
<item name="foo">#FF0099</item>
<item name="bar">#00AAFF</item>
<item name="baz">#FF1100</item>
</style>
</resources>
Why parent
? Maybe our styles need to modify only some small subset of things? Maybe we want to have some defaults for particular values?
So how to apply it? There are several things we need to do:
Context.getTheme().applyStyle(resId, force)
. In the Context
we have a nice method Context.getTheme() This method allows us to apply a particular style on a Theme object. The description of Theme.applyStyle(...)
should give you an idea of possibilities:Place new attribute values into the theme.
For better or for worse, you should do this style application for both activity context and application context.
You do not need to kill the activity, a simple Activity.recreate() will do. Now the fun begins.
Everything might be blinking depending on how your app is designed. Nowadays we have multiple approaches: - multiple activities - single activity - multiple fragments - no fragments - etc etc etc
This has an impact on the final thing. I can tell you only from my own experiences with a single activity + fragments, that if you have several fragment transactions and you will do Activity.recreate()
screen blinks like a disco.
There is a workaround (rather hack-ish). Instead of recreating the whole activity you can only do FragmentTransaction.detach(Fragment).attach(Fragment).commit()
on the top most visible fragment. Other fragments that are not visible should be fine.
Why is this useful:
foo
, bar
, baz
) defined in a style that is child of appGeneralTheme
, you can have those defined elsewhere in any style (if you apply that style it will override)Applicable for anything more then a Theme (colors) in general sense
Upvotes: 7
Reputation: 1759
1- Main Activity Click Event Write :
public onClick(View v){
finish();
Intent intent = new Intent(this, <your_setting _activity>.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);}
2- On Setting Activity Write :
@Override
public void onBackPressed() {
Intent intent = new Intent(this, <your_main_activity>.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
Upvotes: 0
Reputation: 23596
If you want to restart the activity with new theme then you must have to finish it.
other wise if you only want to change the theme (like changig the background, color, button, etc...) then you can made custom theme for your app and then apply that theme as per perticular action.
See: this, and
this` for reference
Hope it will help you.
Upvotes: 1