Android - How to switch theme on runtime - android

Could someone tell me how i can switch the the theme from holo to holo light in my application on runtime ?
I would like to have two buttons in settings to choose light or black theme.
How can it be set applicationwide and not only for the activity ?
I already tried a few things with setTheme() but i wasn't able to change the theme when i click a button.
This is my Settings activity where i would like to set the theme:
public class SettingsActivity extends Activity {
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(android.R.style.Theme_Holo_Light);
super.onCreate(savedInstanceState);
setContentView(R.layout.settings);
}
well this works and my Theme is set but as i am saying i would like to change it systemwide by pressing a button.
Thanks !

As you can see theme is setting on the onCreate() and before setContentView(). So you should call the oncreate() method again when you want to change the theme. But the onCreate() function will be called only once in the life cycle of an Activity.
There is a simple way to do this. I am not sure that it is the best way.
Suppose you want to apply new theme to Activity 1 on a button click.
inside the onClick event
Save the theme to be applied such that it should be retained even after the application restart (preferences or static volatile variables can be used).
Finish the current activity (Activity 1) and call a new activity (Activity 2).
Now in Activity 2
Call Activity 1 and finish current activity (Activity 2).
In Activity 1
Apply the saved theme inside onCreate.
Hope it is not confusing.. :)

You cannot change the theme of other applications (thank goodness).
The only way to somewhat accomplish this would be to create your own build of the operating system with your own theme as the device default theme. However, applications that do not use the device default theme (i.e. they explicitly set the theme to Holo, Holo light, etc) will not get the device default theme.
Edit- To accomplish this application-wide using a base Activity, create an Activity that looks like this:
public class BaseActivity extends Activity {
private static final int DEFAULT_THEME_ID = R.id.my_default_theme;
#Override
public void onCreate(Bundle savedInstanceState) {
int themeId = PreferenceManager.getDefaultSharedPreferences(context)
.getInt("themeId", DEFAULT_THEME_ID);
setTheme(themeId);
super.onCreate(savedInstanceState);
}
}
Then all of your Activities should extend this BaseActivity. When you want to change the theme, be sure to save it to your SharedPreferences.

Related

how to switch android app theme when an android app run

When my android app run, there is a button or something which let customers to select a color to show on primarycolordack, colorprimary and so on. in others words, i want to change app theme. how to do that?
Lucky for you android mead it simple, there is a method for that inside the activity class:
setTheme(android.R.style.MyTheme);
You'll have to call this method inside on create before the super command like this:
public void onCreate(Bundle savedInstanceState) {
setTheme(android.R.style.MyTheme);
super.onCreate(savedInstanceState)
}

Android theme reset after rotation

I provide theme option for my app user. But I found the theme will reset back to default theme after rotation.
Here is my code:
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
config = PreferenceManager.getDefaultSharedPreferences(this);
theme = config.getString("theme", "");
setActionBarTheme(theme);
setContentView(R.layout.main);
}
private void setActionBarTheme(String theme)
{
if(theme.equals("Holo Red"))
{
setTheme(R.style.onTime_Theme_Holo_Red);
}else
{
setTheme(R.style.onTime_Theme_Default);
}
}
This activity is hosting fragments, when device is rotated, fragment remain but theme reset.
If device config changed, it should recreate the activity. Is it bug or I miss something?
As #CBergson pointed out, you can save the theme and recreate it whe the Activity is recreated.
On the other hand you can prevent Android from destroying your Activity by adding the following line to your AndroidManifest.xml:
<activity android:name="YourActivity"
android:configChanges="orientation|screenSize" />
Further reading here.
You should save/update the current theme in your preferences, so that It wont be the default value. Activity life-cycle will repeat itself (stop-destroy-start etc...) when the rotation happens. You need to save it before the cycle is completed before the next activity cycle starts.

overridePendingTransition(R.anim.fadein,R.anim.fadeout);

this code runs after startActivity, but setting it after:
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
keep old (default) android animation. Why?
Because by the time your activity starts and has a chance to overridePendingTransition, the transition has already taken place. You should change the window transitions in a Theme, and set the Activity theme at the manifest.

android - how to update the theme not in the onCreate event?

In my android app, I set the theme like this:
#Override
public void onCreate(Bundle savedInstanceState){
ThemeSetterActivity.setStyle(Main_MenuActivity.this); // this just calls context.setTheme();
super.onCreate(savedInstanceState);
setContentView(R.layout.main_menu);
}
But how do I change the theme using
ThemeSetterActivity.setStyle(Main_MenuActivity.this);
when it's in the onresume event. When I try it, it does call the function but the theme doesn't change. Does it have something to do with not calling:
super.onCreate(savedInstanceState);
setContentView(R.layout.main_menu);
To change the theme of your application during run time, you can use the setTheme(...) method within the activity. You must set the theme to an activity, before loading the views of that activity.
For more info and implementation, refer the link:
Updated
And, as per the docs to set theme you need to restart the entire activity.
You can try this code in onResume() of your activity,
Intent i = getIntent();
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);

Implementing user choice of theme

I want to give the user the choice between a few different themes, and was wondering if this is an alright way of doing things. I did a little test with this method and it worked, but I think there may be better ways and think it may cause some problems later on, so wanted to ask.
I was thinking of creating a different layout for each theme, and in onCreate just having a switch for the setContentView() method. I'd load a saved SharedPreference value (integer) first and depending on what that value was display the corresponding layout. Obviously the user could change the SharedPreference value with a button or something.
As these layouts would be basically the same but with different colours, I'd want to use the same IDs for my TextViews and other Views in each layout file. My main question is would this cause problems?
Sorry for the wall of text with no code. I'd just like to get a general idea of good practice for this situation. Thanks in advance.
I actually have this feature in my application and additionally, I allow users to change theme at runtime. As reading a value from preferences takes some time, I'm getting a theme id via globally accessible function which holds cached value.
As already pointed out - create some Android themes, using this guide. You will have at least two <style> items in your styles.xml file. For example:
<style name="Theme.App.Light" parent="#style/Theme.Light">...</style>
<style name="Theme.App.Dark" parent="#style/Theme">...</style>
Now, you have to apply one of these styles to your activities. I'm doing this in activitie's onCreate method, before any other call:
setTheme(MyApplication.getThemeId());
getThemeId is a method which returns cached theme ID:
public static int getThemeId()
{
return themeId;
}
This field is being updated by another method:
public static void reloadTheme()
{
themeSetting = PreferenceManager.getDefaultSharedPreferences(context).getString("defaultTheme", "0");
if(themeSetting.equals("0"))
themeId = R.style.Theme_Light;
else
themeId = R.style.Theme_Dark;
}
Which is being called whenever preferences are changed (and, on startup of course). These two methods reside in MyApplication class, which extends Application. The preference change listener is described at the end of this post and resides in main activity class.
The last and pretty important thing - theme is applied, when an activity starts. Assuming, you can change a theme only in preference screen and that there's only one way of getting there, i.e. from only one (main) activity, this activity won't be restarted when you will exit preference screen - the old theme still will be used. Here's the fix for that (restarts your main activity):
#Override
protected void onResume() {
super.onResume();
if(schduledRestart)
{
schduledRestart = false;
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
}
scheduledRestart is a boolean variable, initially set to false. It's set to true when theme is changed by this listener, which also updates cached theme ID mentioned before:
private class ThemeListener implements OnSharedPreferenceChangeListener{
#Override
public void onSharedPreferenceChanged(SharedPreferences spref, String key) {
if(key.equals("defaultTheme") && !spref.getString(key, "0").equals(MyApplication.getThemeSetting()))
{
MyApplication.reloadTheme();
schduledRestart = true;
}
}
sp = PreferenceManager.getDefaultSharedPreferences(this);
listener = new ThemeListener();
sp.registerOnSharedPreferenceChangeListener(listener);
Remember to hold a reference to the listener object, otherwise it will be garbage colleted (and will cease to work).
If you are using Material Components themes and followed Light and Dark theme guidelines then you can do it from AppCompatDelegate. These themes can be changed/applied at run time without restarting your application.
private fun handleThemeChange(theme: String) {
when (newTheme) {
getString(R.string.light) -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
getString(R.string.dark) -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
getString(R.string.system) -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}
You can also change dynamically theme using:
ContextThemeWrapper w = new ContextThemeWrapper(this, <newTHEMEId>);
getTheme().setTo(w.getTheme());
Before onCreate for each activity.
It does work if you do it this way, and I don't think it would cause any problem, but it seems like a lot of hassle (you have to multiply all your layouts by all the themes you want to add. If later you want to modify a resource in a layout, you'll have to modify it in all the themes. You're definitely bound to forget one)
Why not using the Styles and Themes feature of Android?
They can be applied to the whole activity easily:
<activity android:theme="#style/my_theme">
So that when you detect a change in the SharedPreferences value you use (button on a preference activity, or something) you can just switch the style. Or better, you can set the style to read your preference value at runtime (when creating the activity) and apply the correct style/theme accordingly.

Categories

Resources