- AndroProgrammer
- Runtime/Dynamically Change Android Application Theme
- Android: Changing app theme at runtime
- Changing the theme at runtime
- Possible issues
- Recursively change attributes on all your Views
- Possible issues
- There is a third option?
- What I recommend
- Do you know a better way of doing this?
- Changing the color scheme at run-time for an Android app (Theme hack?).
AndroProgrammer
Runtime/Dynamically Change Android Application Theme
Before android lollipop most of the apps provides only two or three themes to change at run time because they have already bundled image object for that theme color. I mean images and all selector color are defined and drawable already created with all theme colors because there is no primary color and color accent attribute that allow you to change color dynamically before lollipop. In Lollipop they have add selector that change all objects like edit text and switch with the theme color and that’s very cool. All object look similar and contrasting to your theme.
So how the app developer change themes run time ?
How to change full app theme run time?
Well for answer of above questions go through full tutorial and you will learn how application default theme changed with newly selected color at run time.
Step — 1
Create activity where user can select theme color. in this tutorial it is ChangeThemeDemo. I have taken only two colors but you can add as many as you want. It is really lengthy process but if you go step by step it will be so much easy for you. Now create theme.xml in values folder where you will define all themes that you want to implement. And user can change theme from it run time.
Ok, now your basic theme is set. i have created themes.xml file for only declaring base of theme. You can create your hole theme over here as i have created in styles.xml. check out below code for different themes i have created light and dark and both version of my theme in it.
Step — 2
In step — 1 we have set all things for themes. now in this step i am going to create layout for theme chooser. you can create as you want but for basic setup you can put below code into your activity. it will allow user to select weather they want to apply light or dark theme. i have directly given values for text and padding and margin but for this tutorial only. it is good practice that you declare it in strings.xml and dimen.xml and then apply here. so it will be reusable.
Step — 3
Now to change theme in overall screen in your application you have to put below code in your Base or Main Activity so when ever you start app your your new themes gets apply for whole app. in my case i have BaseActivty which i am extending in all other activities so if i put that code in that activity my whole app themes get changed. MainController is application class in my app you can find code here. you have to put below code before calling super.onCreate(savedInstanceState); because setTheme Method will change theme through out the app.
As i have already told, you don’t have to use strings directly you have to define in strings.xml so if you want to change some thing you have to change it at only one place.
Step — 4
Well now all set, now put below code in Java class in this tutorial it is ChangeThemeDemo.java. where you have to change preference on the basis of user selection. which theme is selected by user and weather light version or dark.
After changing theme you have to restart your activity. you also have to change themes in previous screens also. because they are already opened and in Activity stacktrace. So to change theme in it also i have created TaskStackBuilder. which allow us to recreate Activity stack trace. in my case i have given only two intents but you have to pass activity hierarchy so user don’t know that whole app is restarted.
That’s it from my side. now run the app and see the result. if you have any query or suggestion please let me know in below comment box.
Источник
Android: Changing app theme at runtime
Jun 28, 2015 · 5 min read
Every so often, I see a question posted on StackOverflow which is effectively asks how to change the themes of an app at runtime. The use case is often that there is a setting, button or check box which can switch between different colour themes or between something like day and night mode.
Every time such a requirement comes up, the fir s t thing a quick Google search shows is that it’s not possible to change themes at runtime. That being said, it is possible to change the theme of an Activity, however only in the`onCreate` method and only before `super` is called.
This is problematic because it’s hard to provide a seamless experience to the user if you have to restart the app or Activity in order to change the theme. So our second option is to recursively loop through all of our views and set their attributes each time an Activity or Fragment is created. This way, when the theme is changed, you can loop through all the Views again and change the attributes to reflect the new theme. Neither of these options is ideal, you may even want to consider a hybrid of these two approaches. I’ve provided an example implementation of each of these methods below.
Changing the theme at runtime
As mentioned before, it’s only possible to change the theme of an Activity in the `onCreate` method and that to only before `super` has been called. Changing the theme is fairly straight forward, something like below should do it:
This is pretty straight forward, however this works when an activity is first created and has no effect on the current open Activity or any backgrounded Activities. In order to affect change on the current Activity, we’ll have save the state of the current Activity and relaunch the activity, in order to make this experience seamless for the user, you have 2 options, either remove all transition animations for Activities or change them to provide a nice fade in effect. The result of this approach is shown in the video below.
As you can see, the approach produces a pretty nice result. If you don’t want a fade in effect, remove all animations for Activity transition and you should have a sudden change.
The code to achieve this is in my gist “Transition themes”.
Possible issues
- In order to achieve theme change in this manner, you have to make sure that all your View inherit attributes that matter from the theme and do not in-line any attributes that matter like background colour or text colour.
- Saving your Activity state and relaunching it may not be as smooth as in my example above. This depends a lot of how heavy your Activity and it’s layouts are. Some elements may need to be reloaded.
- Any Activities that are already open in the background will not have the theme change applied to it when you go back to them. The easiest solution to this is to close all the backgrounded Activities, or else, you’ll have to save their state, close them and relaunch them in `onStart` or `onResume`.
Recursively change attributes on all your Views
As much as we hope that the theme can contain all our formatting, we invariably need to override a text colour or background colour in-line in our layout or an in a style attribute and this needs to be changed programmatically. In this scenario, you would likely have to check the appropriate Views or all Views to see if they are consistent with your set theme. If you know which Views are likely to be affected and can check them directly, nothing could be better. If not, you will have to loop through all the View in your layout and check them. The code to do this depends heavily on your project and it’s requirements, however, the skeleton code for checking all your Views be something like this:
Possible issues
- Depending on how complex your screens are, your code for checking each View can become quite complex. An alternate solution can be to set the Views theme related attributes when we build our Activity, Fragment or Layout. This will still add to the complexity of your code.
- There is a time and performance cost to doing this for each layout.
There is a third option?
You could bundle duplicate layouts for each of your themes where the only difference between each layout is that the style or in-line style related attributes are different. Then in your code, depending on the selected theme you inflate or set the appropriate layout. This approach while very simple, however it has the same issues as the first option.
What I recommend
If this is a requirement for your app, I recommend you research what is possible before you try any of these approaches. If all you want to do is change some text colour and the colour of the Toolbar and tabs, this is possible without having to change the theme. I would take a look at the Design Support Library.
If you are going to do down one of the routes I have talked about above, I would recommend not getting too attached to any one approach and to combine all three approaches above. Find the best fit for your particular situation.
Also, if you’re going to need to change the colour of your drawable assets, my article on how to change the colour of drawable assets may help.
Do you know a better way of doing this?
I’m honestly asking the readers, if there are any out there, to chime in and tell me if there is a better way to handle runtime theme changes. It’s a topic I have researched and Google’d, however, I’m just not happy with what I’ve found so far. If you have a better approach or some advice on the matter, I’d love to hear it.
For more Android development article or follow me on LinkedIn, Twitter or Google+.
Источник
Changing the color scheme at run-time for an Android app (Theme hack?).
Righto. Have you ever tried to change the defined theme for your android app at run-time? Perhaps, in response to user input or some user setting you’ve described in your app?
If you have, then I feel a wee bit bad for you, because like me, you probably found out real quick that, android themes? Those little buggers are immutable.
If you haven’t attempted to do that before and this post here is your first foray into changing android themes, then, welcome, you’ve come to the right place.
But, if themes are immutable and cannot be changed at run-time, then what are we doing here?
Well, we are here, because of ThemeOverlays. ThemeOverlays are basically themes that change specific attributes in already defined parent themes, i.e. they change only the items you determine.
Theme overlays, just like normal themes are immutable and cannot be changed at run-time, but since they only change specific attributes (like colorPrimary) and leave all others as they were, we can define multiple overlays and then apply them (like patches) to different activities depending on user input or setting.
To get started, we’ll need a default android theme. The default one created for any new project is fine. It can be found in the styles.xml file and usually looks like this:
Exit fullscreen mode
In this tutorial, we’ll be editing the colorPrimary , colorPrimaryDark and colorAccent attributes (in effect, the title and status bars and things like FABs).
Now, to begin changing themes, we need a couple of colors, we can very well write the color codes in our styles.xml file but I prefer a cleaner approach, so let’s define the colors we want to use in colors.xml . I have chosen these:
Exit fullscreen mode
Twelve colors. Four sets. In each set, one color for colorPrimary , another for colorPrimaryDark and the last for accentColor . Perfect for four different themeOverlays.
Next, we’ll create our actual overlays and use these colors in them.
If you’re following along, jump over to styles.xml and create the themeOverlays you need. I have created mine in this fashion:
Exit fullscreen mode
Notice how I’ve made them all inherit the default AppTheme ? This is incredibly useful if you have other attributes set in the AppTheme style that you want all your overlays to inherit.
Now, we have all our colors and styles set up. How do we use them in activities and such?
Simple! We do that with Theme.applyStyle.
There’s a caveat, however. We can only do applyTheme before we set the content view (i.e. before the layout is inflated).
So, for now, just add the line for applying a theme before setContentView in your activity. The onCreate method should then look like so:
Exit fullscreen mode
The second boolean parameter means to force apply the style.
If you run the app now, you should see a beautiful lime color (or whatever scheme you chose) as the app’s theme.
But. how do we change that if we have to set the theme before setting content view.
To do that, we can simply. restart the activity. Yeah, sorry if that’s not very elegant but I promise it works.
Before we go about that though, we’ll set up a way to keep track of state so that when the activity restarts, the state is preserved and used to set the last selected theme. For simplicity, let’s use SharedPreferences.
Create a SharedPreferences object and a key for the value we’re storing just above the onCreate method like so:
Exit fullscreen mode
Next, we’ll initialize the sharedPreferences object so our onCreate method looks like this:
Exit fullscreen mode
Now, we’ll need four buttons to trigger each of the style changes. Nothing fancy, just normal buttons with a click handler. I’ve created mine in the activity xml file:
Exit fullscreen mode
If you copy-pasted that, you’ll probably have a tiny little error. That’s because we haven’t created our click handler in the activity yet. So, let’s do that next.
We’ll create an onClick handler for all our buttons. This handler will take care of setting the sharedPreferences value restarting our activity. For now, all it does is set our value and it should look something like this:
Exit fullscreen mode
All we’ve done here, is use a when statement (switch in Java) to cater for each button’s click event using their id. And in the event that a button is clicked, we set the shared preferences value to reflect that.
Next, we restart the activity.
To do this, we simply add a few more lines at the bottom of our onClick function. Like so:
Our onClick function should now look like so:
Exit fullscreen mode
What we’ve done is simply getting the current intent and restarting it. I’ve added a no-animation flag so the change is instant and this would hide all animations if we had other activities in our backstack (does not exactly work here because we have just one activity so the entire app is, in effect, getting restarted)
Disclaimer: Rather than going this route, we could use Activity.recreate() , but I don’t particularly like the flicker effect I get with that. (Again, things might be different with a backstack, but feel free to experiment and see which works best for you.)
At this point, we’re 90% done.
The only thing left is to set the theme when our activity restarts based on the current sharedPreferences value. So, we go back to our onCreate method and replace the explicit line to set theme with a conditional. Doing this correctly, our onCreate method looks somewhat like this:
Exit fullscreen mode
Bonus: We can take advantage of the colorAccent attribute of our overlays in any xml files. To demonstrate this, we’ll set the background color of our layout to the colorAccent attribute of the currently applied theme by simply adding this line to layout code:
Exit fullscreen mode
The results of all our trouble so far looks like this:
That’s it, I hope this was helpful. I’ve created an android project with all of the code on GitHub here.
Sources include this StackOverflow answer and the Android Developer docs.
Источник