Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Android inverting some of my drawables for dark theme (night) but not others?

My app uses the Theme.AppCompat.DayNight.NoActionBar AppTheme, and has a navigation drawer. All my drawables are XML vectors and the paths in them are black. For the uses of these drawables that are in the menu in my sidenav, something somewhere in Android or the SDK has inverted the drawable such that my paths are in fact white (or a colour close to white, maybe it's actually colorAccent). This is good.

But when I place the same drawable myself in the action bar as a menu item, it isn't inverted and still uses the black path. How come? How do I get the same magic happening there?

Theme:

<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
    <item name="colorAccent">@color/primaryTextColor</item>
    <item name="android:navigationBarColor">#00000000</item>
</style>

Action bar in the main activity layout:

<androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

menu/action_bar.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <item android:id="@+id/bookmarkAction"
        android:title="@string/bookmark"
        android:icon="@drawable/ic_bookmark_off"
        app:showAsAction="always"
        tools:ignore="AlwaysShowAction" />
</menu>

Here's how I inflate the menu and handle the toggling of the bookmark from the fragment (a ToggleButton did not seem like it would save me any work here):

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
    inflater.inflate(R.menu.action_bar, menu)
    super.onCreateOptionsMenu(menu, inflater)
}

// Swap out the bookmark icon in the options menu depending
// on whether this command is bookmarked or not.
override fun onPrepareOptionsMenu(menu: Menu) {
    super.onPrepareOptionsMenu(menu)

    val bookmarkMenuItem = menu.getItem(0)
    val commandName = viewModel.command.value?.name

    if (model?.bookmarkedCommands?.contains(commandName)!!) {
        Log.v(logTag, "${commandName} is bookmarked")

        bookmarkMenuItem?.icon = ContextCompat.getDrawable(requireContext(),
            R.drawable.ic_bookmark_on)
    }
    else {
        Log.v(logTag, "${commandName} is not bookmarked")

        bookmarkMenuItem?.icon = ContextCompat.getDrawable(requireContext(),
            R.drawable.ic_bookmark_off)
    }
}

Sidenav icons, inverted (good):

sidenav

Action bar icon, not inverted (bad):

enter image description here

like image 243
Eliot Avatar asked Jul 21 '20 06:07

Eliot


People also ask

How do I apply a Dark theme to all apps on Android?

Turn Dark theme on or off in your phone's settings Important: When you turn on Dark theme for your phone, many apps also use Dark theme. On your phone, open the Settings app. Tap Display. Turn Dark theme on or off.

How do I handle Dark theme on Android?

Use the system setting (Settings -> Display -> Theme) to enable Dark theme. Use the Quick Settings tile to switch themes from the notification tray (once enabled). On Pixel devices, selecting the Battery Saver mode enables Dark theme at the same time.

Why is Google background black on Android?

Google Chrome has a feature called Dark mode (or Dark theme on Android devices) that is aimed to provide a comfortable Web browsing experience when in low light. It turns the interface as well as elements including your homepage, toolbar, and settings into a dark colour scheme to help reduce eyestrain.


1 Answers

I was 99% sure AppCompat’s Toolbar or at least MaterialToolbar would automatically tint with a theme attribute, but it doesn't look like it.

To answer your question "Why is Android inverting some of my drawables for dark theme (night) but not others?", it'll be because the components which are using the drawables don't tint using theme attributes.


There's a few ways you can achieve what you want. These all assume you want it to be colorControlNormal, otherwise choose whatever color attribute you'd prefer.

colorControlNormal has default values in AppCompat (dark gray-ish) and it's white in the values-night variant (which you'd get from using a DayNight theme).

Set the icon tint in the vector drawable

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:tint="?attr/colorControlNormal"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="#FF00FF"
        android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z" />
</vector>

This would have the potentially undesirable effect of tinting this drawable somewhere else that you're using it (depending on whether the other place applies its own tint).

Set icon tint in the menu

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <item android:id="@+id/bookmarkAction"
        android:title="@string/bookmark"
        android:icon="@drawable/ic_bookmark_off"
        app:iconTint="?attr/colorControlNormal"
        app:showAsAction="always"
        tools:ignore="AlwaysShowAction" />
</menu>

This one will override the tint in the drawable, if one is set.

like image 146
ataulm Avatar answered Oct 11 '22 20:10

ataulm