I'm trying to implement dark mode in my application. As far as I know, the best solution is to use Paris library. Is there any simple solution to set dark mode globally in the application?
I found issue on the Paris github: https://github.com/airbnb/paris/issues/15 but it is not implemented. Any idea is there another way to set style once and not using view.style(R.style.night_style) on each view?
You can use different themes like below example :
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight"></style>
Alternatively, if you want to define separate Light and Dark themes for your app, you can inherit from Theme.MaterialComponents.Light in the values directory, and Theme.MaterialComponents in the values-night directory. E.g.:
res/values/themes.xml
<style name="Theme.MyApp" parent="Theme.MaterialComponents.Light">
<!-- ... -->
</style>
res/values-night/themes.xml
<style name="Theme.MyApp" parent="Theme.MaterialComponents">
<!-- ... -->
</style>
The Theme.MaterialComponents theme is a static dark theme, whereas
Theme.MaterialComponents.DayNight is a more dynamic theme which will
help facilitate easy switching between your app’s Light and Dark
theme. If using a DayNight theme, you can define one app theme that
references color resources, which can be overridden in the
values-night directory if needed.
Reference
Related
I'm using the Material Component's dark theme style, everything is working fine but now I need to show a particular view with a different theme to obtain more contrast.
I've defined my main theme in values/themes.xml like that:
<style name="Base.AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">#color/color_primary</item>
<item name="colorPrimaryVariant">#color/color_primary_variant</item>
<item name="colorOnPrimary">#color/color_on_primary</item>
...
</style>
and two different colors resources in values/colors.xml and values-night/colors.xml.
What I would like to do is to find a way to retrieve the light theme colors when the dark theme is used (and vice-versa) or to apply the opposite theme to a single view.
The only solution I found was to simply define two variants (normal and "reversed") for each color in both colors.xml files, but since there are many colors defined I would like to avoid that.
To avoid having to define multiple light/dark values variant for each color, I defined a custom style that refers to the opposite theme variant, e.g. in values/styles.xml I defined:
<style name="ThemeOverlay.AppTheme.Reverse" parent="ThemeOverlay.MaterialComponents.Dark"/>
and in values-night/styles.xml:
<style name="ThemeOverlay.AppTheme.Reverse" parent="ThemeOverlay.MaterialComponents.Light"/>
Then in the root of layout where I want to use the "reversed" theme:
<LinearLayout android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppTheme.Reverse">
...
</LinearLayout>
I get this as one of my colors generated by the Material Design Color Platte.
But in this image:
I don't see colorPrimaryLight anywhere. What is it used for and how do I declare it? Do declare it like this in my style?:
<item name="colorPrimaryLight">#color/colorPrimaryLight</item>
Or do I declare it in a different way? And what is it used for?
By default, the statusBarColor is set to colorPrimaryDark. If you want to use colorPrimaryLight for the status bar you need to set android:statusBarColor to android:colorPrimaryLight.
https://developer.android.com/training/material/theme.html
in your resources file put:
<color name="colorPrimaryLight">#D1C4E9</color>
in your styles file put:
<item name="colorPrimaryLight">#color/colorPrimaryLight</item>
TL;DR: colorPrimaryLight is one of several colors identified as part of the Material palette that is not actually mapped to a Theme attribute in Android. The guidelines recommend using it in several areas such as a TabLayout backgrounds.
I cannot find an authoritative source about using this attribute in Android apps, but it seems that Material defines a large number of colors, as shown on this helpful page, but not all of them are mapped to Android Theme attributes. For instance, if you create a brand new single-Activity project in Android Studio and modify styles.xml as shown below:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<!-- THIS THEME ATTRIBUTE IS NOT FOUND -->
<item name="colorPrimaryLight">#color/colorPrimary</item>
</style>
</resources>
The colorPrimaryLight attribute is not found by the compiler.
Therefore if you wanted to use it in your application you would presumably have to explicitly link to a color.xml resource. This seems to negate the benefit of the Theme system somewhat, but perhaps I am missing a trick.
Starting to get my hands into that new update to the Google Support Library and I want to implement the Theme.AppCompat.DayNight into my app.
The problem I am having is that it seems no one explained how to customize it. So If I want to have a different colorAccent for day and a different one for night, how do I do that? Are you supposed to specify different dark and light themes to base off of? Thanks in advance!
You can use the night resource qualifier folder.
In this way you can define colors and the other resources for the dark (night) and for the light theme (day).
Qualifiers:
night: Night time
notnight: Day time
In order to support the dark theme with a Material Components Theme use:
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight">
<!-- ... -->
</style>
With an AppCompat theme:
<style name="AppTheme" parent="Theme.AppCompat.DayNight">
<item name="colorPrimary">#color/primary</item>
</style>
Then define in your app theme the references color resources, and override the value in the values-night directory if needed:
Example: res\values\colors.xml:
<color name="colorPrimary">.....</color>
In res\values-night\colors.xml folders define the same color:
<color name="colorPrimary">.....</color>
I have an app with a few different Activities. The different activities have different styled buttons, texts, etc... I've set up all the components to have various styles based on their location/Activity. (Eg. style="#style/MainMenuActionBarTitle, or style="#style/MainMenuActionBarTagLine). These styles set the background (Drawable, MipMap, or Color), textColor, etc...
The app will be offering some theme packs which change the colors of these various components throughout the application, and I was hoping there was a way to have Styles with the same name, but different values based on the Theme of the app. This way I can just change the Theme whenever the Activity is loaded to whatever Theme the user has chosen.
There's some good info here on how to change the standard widget look & feel using Themes, but that changes the look and feel for the standard-un-styled widgets.
Is there a way to accomplish this using Themes, or is this the wrong direction altogether? Is there a better/easier route?
Edit: After doing more research and more fiddling, I've realized what I want to do isn't far off from how I can accomplish this. What I want to do is to actually change component Styles when I set the Theme of the Activity.
One solution I've discovered is to use attributes which the Theme can point to different Styles.
attrs.xml
<resources>
<!-- Attributes referencing whatever style the theme needs to set up. -->
<attr name="main_menu_button_style_play" format="reference" />
</resources>
themes.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- App specific attributes -->
<item name="#attr/main_menu_button_style_play">#style/MainMenu.Button.Play</item>
</style>
<!-- Blue application theme. -->
<style name="AppTheme.Blue" parent="AppTheme">
<!-- App specific attributes -->
<item name="#attr/main_menu_button_style_play">#style/MainMenu.Button.Play.Blue</item>
</style>
</resources>
styles.xml
<style name="MainMenu.Button.Play">
<item name="android:background">#f76d3c</item>
<item name="android:text">PLAY</item>
</style>
<style name="MainMenu.Button.Play.Blue">
<item name="android:background">#2ca8c2</item>
</style>
activity.xml
<Button android:id="#+id/main_play_button"
style="?attr/main_menu_button_style_play"/>
This works really well, and allows me to set the Theme in the Activity.onCreate() method.
The only annoying problem I have with this solution is that Android Studio complains that the Button is missing the layout_width and layout_height even though they're defined in the Style. I guess it doesn't follow the attribute reference back through the chosen Theme.
Another approach which is what I ended up using was to more heavily use the attributes. Creating attributes for all the properties values I want to change between themes. So, instead of main_menu_button_style_play which defines the style reference, I used main_menu_button_play_background. This approach is the same amount of work as simply specifying a style because themes can inherit, but the IDE understands it.
A user-selectable theme (light and dark), with each theme having its own resources, is straightforward to implement if a single parent theme is used in the app:
<style name="MyApp.Dark" parent="android:Theme.Material">
<item name="themeBackground">#color/dark_grey</item>
<item name="themeBackgroundTransparent">#color/darkColorBackgroundTransparent</item>
<item name="colorPrimary">#color/darkColorPrimary</item>
.
.
</style>
<style name="MyApp.Light" parent="android:Theme.Material.Light">
<item name="themeBackground">#color/brown_50</item>
<item name="themeBackgroundTransparent">#color/lightColorBackgroundTransparent</item>
<item name="colorPrimary">#color/lightColorPrimary</item>
.
.
</style>
However, a typical Android app might employ multiple parent themes throughout the app such as the dialog theme, no action bar theme, or dialog-when-large theme. These themes would not be covered by current themes extending Theme.Material (because inheritance is expensive), so using these themes would necessitate additional style definitions for light and dark themes:
<style name="MyApp.DialogWhenLarge.Light" parent="android:Theme.Material.Light.DialogWhenLarge">
</style>
<style name="MyApp.DialogWhenLarge.Dark" parent="android:Theme.Material.DialogWhenLarge">
</style>
In order to apply themed resources to the new themes, the trivial solution is to copy and paste individual items from the MyApp.Dark theme into the new MyApp.DialogWhenLarge.Dark theme, et al, but the amount of duplicated code becomes unmanageable, incomprehensible, and error-prone with increasing numbers of themes and resources.
So my question is, what is a simple way to apply themed resources to multiple theme definitions?
Ideally, one would be able to apply a set of resources to a theme in the same way one would applies a style to a view, which would result in a solution of the following form:
<style name="MyApp.DialogWhenLarge.Light" parent="android:Theme.Material.Light.DialogWhenLarge">
<item name="themedResources">[pointer to canonical list of light theme resources]
</style>
Of course, it is also important that any solution retains the ability to reference themed resources from views in the format of ?themeBackground