The inbox app features a navigation drawer. Upon clicking on any navigation drawer item a fragment is loaded (most probably) and during this transaction the app theme changes. Changing app theme requires setTheme() method to be called before setContentView(..) in the onCreate() method of the activity. The super fluid UI indicate the use of fragments so how is this achieved without recreating parent activity (otherwise there would have been a lag for sure).
The snooze fragment hase oragne like theme
The inbox fragment has blue like them
You can actually change the theme's style, but only before calling setContentView(#ResId int) method. Something like this perhaps?
getTheme().applyStyle(isDashUser ? R.style.redStatusBar : R.style.blackStatusBar, true);
setContentView(R.layout.my_activity);
If you look closely when changing the page there's a slight graduation between the two colours. This probably suggests they have a system separate from theming to re-colour all the UI elements.
One my apps has a very similar colour change feature, and I just have methods set up to manually re-apply the relevant colours to each UI element. Of course Google probably have some super slick way of doing it that they'll never share with anyone.
Related
I'm trying out the single activity approach together with the Navigation Component but I was wondering how to apply multiple themes to one activity.
Normally I would set a theme to an activity via the AndroidManifest.xml and all the fragment within that activity will use that same styling. Whenever I want to use another theme I would simply create another activity and apply the other styling. But since there only is one activity I would have to change the styling after the activity has been created. This is fine for styling used by Fragments. However styles for the StatusBar and NavigationBar are a lot harder because they affect the Activity.
Things I've tried:
Change the theme of the Activity after is has been created. Unfortunately these changes aren't applied directly and would require a restart of the activity (which is the one currently running).
Set styles like StatusBar and NavigationBar when creating the Fragment. This works, but it requires me to set the themes and styles using code instead of using the usual themes.xml and styles.xml.
Can anybody tell me what the intended solution is? Because of these limitations we started adding activities again to the navigation component whenever the theme needed to be changed.
I have a PreferenceFragment and I want to change the background, text color, and a couple other things however I can't find a way to change the fragments style without affecting other fragments in my app.
I tried a solution mentioned at Applying custom theme to ActionBar in PreferenceFragment
which said to put getActivity ().setTheme (R.style.myCustomTheme); in onCreate however that affects all of my other fragments since they are using the same activity as the PreferenceFragment.
Is there a way to change only the PrefrenceFragment style without affecting the activity/other fragments?
Thanks!
EDIT: I guess I could make it a seperate activity and change the theme that way but I would really like to keep it a fragment if possible.
I'm targeting API level 14+, so I've used Activity.recreate() for theme switching in my app. It worked out nice, except a black screen will flash for about 0.5s.
I used to think it is impossible to provide a better experience here, until I saw a material designed app which successfully switched its theme with a crossfade. But unluckily I failed to recall its name since I uninstalled it from my phone some time ago.
I've tried Activity.overridePendingTransition(), it did not work, and I believe the reason is that the recreate() call is much like a configuration change so the mechanism is different from finishing and launching a brand new activity.
(And while trying to find that app I came across another magic theme switching app, even without calling recreate(). Hum... Anybody know how the trick is done?)
Theme switching on the fly GIF
Who said themes were immutable? Changing the primary and accent colors on…
EDIT:
I found that the GIF above is kind of a distraction from the original question, so I turned it into a link.
My original question is that, is there any method to change (switch) theme with an appropriate transition?
Changing all the things on screen by Brute force is not switching the app's theme; it just appear to be though, but it can lead to many problems.
Sad to find out the above GIF may only be a hacky brute force attack, but still thanks to #Emanuel Moecklin for pointing this out.
But I still hope a "(truly) switching theme with transition" solution can come up, or someone tell me that Activity.recreate() cannot be animated and no other ways can switch themes better.
After all these years I've learned an easy way.
Instead of Activity.recreate(), use the follwing code fragment:
finish();
startActivity(new Intent(this, getClass()));
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
And it will give you a nice animation between themes.
Bonus: You can manually save & restore instance state to preserve UI state, and ignore user input during restarting by overriding input related methods (dispatch*Event()) on Activity.
Check out this answer to a similar question:
https://stackoverflow.com/a/26511725/534471
What the app you mention in your question does, isn't changing the theme but changing the color of the status bar, the action bar and the navigation bar:
Status Bar:
getWindow().setStatusBarColor(colorStatus);
Action Bar:
ActionBar actionBar = getSupportActionBar();
actionBar.setBackgroundDrawable( new ColorDrawable( colorAction ) );
Navigation Bar:
getWindow().setNavigationBarColor(colorStatus);
My guess is that the accent color is changed by just setting the background color of the two visible elements (the floating action button and the tab navigation). Tab navigation colors can be changed like this:
ActionBar actionBar = getSupportActionBar();
actionBar.setStackedBackgroundDrawable( new ColorDrawable( accentColor ) );
I want to have a "change theme" feature in my app. If I call setTheme() in onCreate(), there is one problem.
The moment after I launch my app, a plain white background appears for a second (because I have set light theme in the manifest). After that, the complete layout of my Activity is displayed - it is either with white or black background, according to user's theme preference.
Is there any way I can change whether white or black background appears after launch?
Make sure you call setTheme() in onCreate() BEFORE calling setContentView(). Then if you want to dynamically change the theme again later, you should simply restart your activity.
If you are adding a theme to the entire program than you could start by doing:
In your manifest you add to your application tag that you are using a theme.
<application android:theme="#style/mythemename">
Then look at Theme XML to make sure that you have what you need declared in the appropriate places.
If it is just for a particular action you could add the activity tag
<activity android:theme="#android:style/Theme.propertyname">
You can also, if you want your theme to just change the background color, follow the same pattern with either the activity or application tag (what ever one you are using) and set the item name "colorbackground" to what you want.
You can also use Theme XML and remake what you want in your current theme and call that your custom theme using the method above.
I hope this helps and if not please let me know so I might be able to help better in the future.
Another way would be to have a kind of splash screen which will check for a preference variable for example and then decide whether to use the light or the dark theme. This way you could also use XML layouts.
EDIT: Yet another way is to have the all the layout defining stuff in the onCreate() method and then just trigger the onStart() method when ready.
Did anyone implemented multi theme support for android app? Are there any common practices for this?
Thanks for any advice.
UPD: The main problem for now is that android's theme engine doesn't support selectors like in CSS. For example if I have two views with "background" attribute there's no way to make theme engine distinguish those ones and set different backgrounds. I can specify different style for each view but this approach lacks flexibility 'cause it's impossible to apply style for whole activity at once.
As far as I know, there is no way to set a theme to the whole application in on line of code. If you want to change the theme of an activity, you need call setTheme() in its onCreate() method, BEFORE calling setContentView. So to make it easier for you, you could do a switch on all your themes, and select one in regards of what the user has selected. Now, if you want it to apply easily to all your activities, you could make all your activities be a subclass of a custom Activity in which you would only set the theme. Activity <-- ThemeActivity <-- all your Activities