Set theme programatically to Android system preview window - android

I have an app in which the user can choose between the default theme and a dark theme. The manifest applies AppTheme to the <application>, while each activity checks the relevant flag and uses setTheme(AppTheme.Dark) if necessary.
This implementation works well for all my activities, but the preview window shown by the OS before the application launches uses the Manifest theme, i.e. the light one. So users get a sudden white screen before reaching the dark app.
Based on other SO answers, I gathered that the only customization we can do is to set a windowBackground drawable for the window to use (and a statusBarColor if needed).
Even though I have two different windowBackground set for each theme, I can't change the theme for the preview window since the Application class seems to load after it, and setting theme there makes no difference.
I'd like to avoid disabling the preview since it adds a noticeable delay without much indication that the app is launching. Is there any solution to this? I'm considering having a dark color for both themes in the worst case, like the Reddit app does.
Styles:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- primary and accent color attributes -->
<item name="android:windowBackground">#color/activityBackgroundLight</item>
</style>
<style name="AppTheme.Dark" parent="AppTheme">
<!-- primary and accent color attributes -->
<item name="android:windowBackground">#color/activityBackgroundDark</item>
</style>
Note: While I'm using colors here, I've already tried with a gradient drawable and it doesn't change anything.
UPDATE: I wasn't able to get any other method, so I went ahead and applied the dark theme by default on the SplashActivity. This means the preview window is always dark, while the check in the SplashActivity's onCreate is inverted (compared to other activities) and applies the light theme if needed.
Still looking for a solution that actually lets me switch at runtime.

Related

Android - System doesn't recognize my theme as dark mode

I have two themes. One is:
<style name="ThemeDay" parent="Theme.AppCompat.Light.NoActionBar">
Other one is:
<style name="ThemeNight" parent="Theme.AppCompat.DayNight.NoActionBar">
I apply themes in every activity like this before super.onCreate()
if(GenelUtil.getNightMode()){
setTheme(R.style.ThemeNight);
}else{
setTheme(R.style.ThemeDay);
}
Theme is applied. But system doesnt behave like selected theme.
For example when system is light mode and app is dark mode, Navigation bar is still white, dialogs are still white etc..
But when I open instagram and switch to dark mode, system also behave like its in dark mode.
What do I do wrong here? How can I fix this?
DayNight theme is picking automatically dark or light params/colors basing on system settings (by default) or set/forced by you (e.g. using AppCompatDelegate.setDefaultNightMode())
when you have light theme in your system and you will use DayNight theme for your app then still not overriden colors will be same as in "light" theme

How come the color I set for cardBackgroundColor isn't exactly the one that gets shown?

Background
I'm trying to prepare dark theme for an app, and one of the requirements is to have a specific color for cards and dialogs : #ff3c454c
The problem
Whether I set it by force ( app:cardBackgroundColor="#3c454c") , by reference ( app:cardBackgroundColor="#color/...) or just in the theme - in all cases I don't get the color I've set. Instead I get the color of #525A61.
I've tested just a red color (#f00) just to be sure it affects the card, and it does, and for this color it indeed gets to be fine. But for the color I've set, it doesn't.
What I've tried
As I wrote, I tried multiple ways to set the color. In the beginning I wanted to use just the theme itself, so I've set it as such:
styles.xml
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
...
<item name="colorBackgroundFloating">#color/colorBackgroundFloating</item>
<item name="colorSurface">#color/colorBackgroundFloating</item>
</style>
res/values-night/colors.xml
<color name="colorBackgroundFloating">#ff3c454c</color>
Later I tried to use the color directly and even set it as hard coded. Still got the incorrect color when it gets shown.
Seeing this could be a bug on the library itself, I've reported about this here (include a sample project, if you wish to check it out).
I've noticed the exact same issue occurs for BottomNavigationView and probably other similar cases.
The question
Why does it occur?
Is there any workaround for this?
Something that will fix it globally for all views that use these attributes ?
What you are seeing is the elevation overlay that they introduced to make elevation more noticeable while in Dark Theme, where shadows are not so visible. You can read about it here : https://material.io/develop/android/theming/dark/ in the section "Elevation Overlays"
The simple solution if you don't want this behavior is to add this to your theme.
<item name="elevationOverlayEnabled">false</item>
And you can also adjust it to another color or even a more subtle version of the overlay by changing the alpha:
<item name="elevationOverlayColor">#80FFFFFF</item>
EDIT with more info from https://github.com/material-components/material-components-android/issues/1133
If you want to disable it for only one component or widget, you can define a style for it with a theme overlay and use it in a specific layout:
<style name="ThemeOverlay.MyApp.ElevationOverlayDisabled" parent="">
<item name="elevationOverlayEnabled">false</item>
</style>
<style name="Widget.MyApp.CardView" parent="Widget.MaterialComponents.CardView">
<item name="materialThemeOverlay">#style/ThemeOverlay.MyApp.ElevationOverlayDisabled</item>
</style>
And if you want to disable it for all cards in your app but keep it in other components you can set that style as the default style for material card views:
# Set in your app theme
<item name="materialCardViewStyle">#style/Widget.MyApp.CardView</item>

How do I force apply a dark theme on Android?

According to the docs, I only need to set android:forceDarkAllowed=true in my activity manifest and inherit theme from parent="Theme.MaterialComponents.DayNight". I tried that, but it didn't work.
Here's my manifest file:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:forceDarkAllowed="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
And here's my styles.xml styles:
<style name="AppTheme" parent="Theme.MaterialComponents.Light">
...
</style>
<style name="AppTheme.Dark" parent="Theme.MaterialComponents.DayNight">
...
</style>
I tried to get the theme name of the activity by using this code below:
resources.getResourceName(
packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA)
.applicationInfo.theme
)
It shows me com.example.name:style/AppTheme and not AppTheme.Dark. How can I make it so that when I run the application, the MainActivity automatically sets itself to use AppTheme.Dark (i.e. dark mode) using android:forceDarkAllowed?
That is not how dark mode works on Android 10.
First, Android does not magically append .Dark to your theme at any point, regardless of whether or not the user enabled dark mode. You have android:theme="#style/AppTheme". So, Android will use AppTheme all the time, and your AppTheme.Dark will not be used.
Second, the idea behind DayNight is that you use that as you base theme all the time, and Android will switch between normal and dark modes based on user request. So, if you switch AppTheme to extend DayNight, and get rid of AppTheme.Dark, you will be matching what the documentation calls for.
android:forceDarkAllowed is for cases where you are not in position to use a DayNight theme, and you want Android to try to automatically convert your UI to a dark theme. If you wanted to keep AppTheme extending Light instead of DayNight, this might work (I personally have not tried it with a MaterialComponents theme). But, even then, it will only be when the user has enabled dark mode (e.g., tapped on the notification shade tile).
For example, in this sample app, I use DayNight for my theme:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.DayNight">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
</resources>
I have different definitions for those colors in res/values/ and res/values-night/. I do not use forceDarkAllowed. And, when the user toggles night mode, my UI goes from:
to:
How can I make it so that when I run the application, the MainActivity automatically sets itself to use AppTheme.Dark (i.e. dark mode) using android:forceDarkAllowed?
You don't.
If you want a dark theme all the time, use a regular theme (not Light, not DayNight).
If your app uses a dark theme (such as Theme.Material), Force Dark will NOT be applied. Similarly, if your app's theme inherits from a DayNight theme, Force Dark will NOT be applied, due to the automatic theme switching.
Dark theme is available in Android 10 (API level 29) and higher. Make sure that your device's API level is 29 + that your target SDK in the gradle is 29.
There are two ways to apply dark theme:
DayNight - custom-able theme - you control how dark/light theme will look like
Force dark - you control the light theme, and if the user chooses dark mode the system will convert your views to dark theme at runtime.
There are settings to allow dynamically setting day or night regardless of the current system setting.
Each of the options map directly to one of the AppCompat.DayNight
modes:
Light - MODE_NIGHT_NO
Dark - MODE_NIGHT_YES
System default - MODE_NIGHT_FOLLOW_SYSTEM
To switch the theme, call AppCompatDelegate.setDefaultNightMode().
https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#change-themes
This would apply to setting a DayNight theme. If you are trying to take advantage of the Force Dark in Android 10, it applies to the .Light sub-themes. It will not be applied to any of the DayNight or inherently dark themes.
Apps must opt-in to Force Dark by setting
android:forceDarkAllowed="true" in the activity's theme. This
attribute is set on all of the system and AndroidX provided light
themes, such as Theme.Material.Light.
https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#force-dark
Below that, the documentation also specifies how to exclude certain items, either in resources or code.
Force Dark can be controlled on specific views with the
android:forceDarkAllowed layout attribute or with
setForceDarkAllowed().
Beyond that, there are ways to detect the current system light / dark setting and respond to it using the options above, but that is for another post.
It's not a great solution for a dark theme and I apologize for any overlap with the accepted answer, but I do not agree with claiming something isn't possible because it isn't preferred.

Android application Theme overriding view theme

I have been developing an Android app for quite some time now and almost everything is how it's supposed to be. However, I'm having some issues with themes for some views. My application uses a AppCompat.Light based theme as shown bellow:
<style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar"></style>
Everything looks white and clean, but I have one specific screen that is kind dark. So I created the following theme for some EditText fields:
<style name="InputField" parent="Theme.AppCompat"></style>
in order to make the input fields have white colors. I then run the application on devices with different Android versions. On a smartphone with Android 5.0.2, everything looks as I expected. On a smartphone with android 4.4.4, however, the input is dark. I even tried to change the theme of the input field theme to
<style name="InputField" parent="Theme.Holo"></style>
or
<style name="InputField" parent="#android:style/Widget.Holo.EditText"></style>
in the values-v19 styles, but it still looks dark. If I change the application theme to
<style name="AppBaseTheme" parent="Theme.AppCompat.NoActionBar"></style>
the input fields look as they should, but the entire rest of the app is dark themed and it's not what I want. I can only assume that application theme is having some influence over my views theme, even though I explicitly specified the theme they should use. The same behavior happens on a smartphone with android 4.2.2.
System provided styles doesn't define used colors, they have only references to a theme attributes. Colors are defined the theme, thus, it not enough, if you set parent to some system style.
Starting API 21 (5.0) you can override theme for specific views (or styles) by setting attribute android:theme. For older versions you will need to define specific colors and drawables in your style.

Designing Android Themes

Can anyone tell me how I can change my apps theme from the default ones made available? Holo and Holo.Light get a bit boring after a while.
The likes of Facebook, Google+, BBC Weather, Viber, Vine and Twitter all look very professional and have their own theme whereas the app I'm developing looks quite boring.
Is it possible to change the font of the text in my app? I know it's possible to change the colour and size of it.
Another thing which would be useful to know would be how to change the colour of the action bar that is used for my app. Currently it's black but I wouldn't mind changing it to a different colour than those used by the Android default themes (e.g. purple, green, blue, etc)
Maybe you can share some tips on what you think works well for Android design?
You can generate a custom theme at http://jgilfelt.github.io/android-actionbarstylegenerator/
If you only want to change a few font an colors etc take a closer look at this (source:http://developer.android.com/guide/topics/ui/themes.html)
If you like a theme, but want to tweak it, just add the theme as the parent of your custom theme. For example, you can modify the traditional light theme to use your own color like this:
<color name="custom_theme_color">#b0b0ff</color>
<style name="CustomTheme" parent="android:Theme.Light">
<item name="android:windowBackground">#color/custom_theme_color</item>
<item name="android:colorBackground">#color/custom_theme_color</item>
</style>
(Note that the color needs to supplied as a separate resource here because the android:windowBackground attribute only supports a reference to another resource; unlike android:colorBackground, it can not be given a color literal.)
Now use CustomTheme instead of Theme.Light inside the Android Manifest:
<activity android:theme="#style/CustomTheme">

Categories

Resources