Menuitem Tinting on Appcompat Toolbar

MenuItem tinting on AppCompat Toolbar

Because if you take a look at the source code of the TintManager in AppCompat, you will see:

/**
* Drawables which should be tinted with the value of {@code R.attr.colorControlNormal},
* using the default mode.
*/
private static final int[] TINT_COLOR_CONTROL_NORMAL = {
R.drawable.abc_ic_ab_back_mtrl_am_alpha,
R.drawable.abc_ic_go_search_api_mtrl_alpha,
R.drawable.abc_ic_search_api_mtrl_alpha,
R.drawable.abc_ic_commit_search_api_mtrl_alpha,
R.drawable.abc_ic_clear_mtrl_alpha,
R.drawable.abc_ic_menu_share_mtrl_alpha,
R.drawable.abc_ic_menu_copy_mtrl_am_alpha,
R.drawable.abc_ic_menu_cut_mtrl_alpha,
R.drawable.abc_ic_menu_selectall_mtrl_alpha,
R.drawable.abc_ic_menu_paste_mtrl_am_alpha,
R.drawable.abc_ic_menu_moreoverflow_mtrl_alpha,
R.drawable.abc_ic_voice_search_api_mtrl_alpha,
R.drawable.abc_textfield_search_default_mtrl_alpha,
R.drawable.abc_textfield_default_mtrl_alpha
};

/**
* Drawables which should be tinted with the value of {@code R.attr.colorControlActivated},
* using the default mode.
*/
private static final int[] TINT_COLOR_CONTROL_ACTIVATED = {
R.drawable.abc_textfield_activated_mtrl_alpha,
R.drawable.abc_textfield_search_activated_mtrl_alpha,
R.drawable.abc_cab_background_top_mtrl_alpha
};

/**
* Drawables which should be tinted with the value of {@code android.R.attr.colorBackground},
* using the {@link android.graphics.PorterDuff.Mode#MULTIPLY} mode.
*/
private static final int[] TINT_COLOR_BACKGROUND_MULTIPLY = {
R.drawable.abc_popup_background_mtrl_mult,
R.drawable.abc_cab_background_internal_bg,
R.drawable.abc_menu_hardkey_panel_mtrl_mult
};

/**
* Drawables which should be tinted using a state list containing values of
* {@code R.attr.colorControlNormal} and {@code R.attr.colorControlActivated}
*/
private static final int[] TINT_COLOR_CONTROL_STATE_LIST = {
R.drawable.abc_edit_text_material,
R.drawable.abc_tab_indicator_material,
R.drawable.abc_textfield_search_material,
R.drawable.abc_spinner_mtrl_am_alpha,
R.drawable.abc_btn_check_material,
R.drawable.abc_btn_radio_material
};

/**
* Drawables which contain other drawables which should be tinted. The child drawable IDs
* should be defined in one of the arrays above.
*/
private static final int[] CONTAINERS_WITH_TINT_CHILDREN = {
R.drawable.abc_cab_background_top_material
};

Which pretty much means they have particular resourceIds whitelisted to be tinted.

But I guess you can always see how they're tinting those images and do the same. It's as easy as set the ColorFilter on a drawable.

Why some menu item in the toolbar appears in a different colour?

I can't explain why the search icon is not white when you run the app, but the help icon clearly is marked to be tinted blue (android:tint="#145979"). android:tint in the parent vector element overrides the color of any child path elements.

I suggest you set android:tint="?android:attr/colorForeground" in the top level vector element of all of these so they can follow your theming. Then if you decide to make them a different color or have a day/night theme where they are a different color during the day, you only have to change it in the theme in one spot, and they will always match the overflow icon color.

If you want white text and icons on your action bar, I suggest you use a parent theme that has DarkActionBar in its name, or if you are using NoActionBar and including a Toolbar in your layout that you set as the support action bar, then set an actionBarTheme with a DarkActionBar parent, such as including:

<item name="actionBarTheme">@style/ThemeOverlay.MaterialComponents.Dark.ActionBar</item>

This will make the overflow icon white as well.


Edit: I realized the above only works if you use a theme with a window decor action bar instead of a NoActionBar theme with a Toolbar in the layout.

The help icon needed its tint changed to white in the XML.

From the comments: The search button was getting externally tinted because of it having actionViewClass in the menu XML. It was using colorOnPrimary from the theme to tint its icon. So instead of just using @style/ThemeOverlay.MaterialComponents.Dark.ActionBar as the actionBarTheme, you had to create a custom action bar overlay theme and use that.

<style name="MyThemeOverlay_Toolbar" parent="ThemeOverlay.MaterialComponents.Toolbar.Primary">
<item name="colorOnPrimary">@color/colorWhite</item>
</style>

<!-- and inside the app theme: -->
<item name="actionBarTheme">@style/MyThemeOverlay_Toolbar</item>

Toolbar icon tinting on Android

I see this question is getting some views so I'm going to post an answer for those who don't read the comments.

My conjectures in the question were all wrong and it is not a matter of alpha channels, at least not externally. The fact is simply that, quoting @alanv ,

AppCompat only tints its own icons. For now, you will need to manually
tint any icons that you're providing separately from AppCompat.

This might change in the future but also might not. From this answer you can also see the list of icons (they all belong to the internal resource folder of appcompat, so you can't change them) that are automatically tinted and with which color.

Personally I use a colorControlNormal which is black or white (or similar shades), and import the icons with that particular color. Colored icons on a colored background look a little bad. However, another solution I found pleasant is this class on github. You just call MenuColorizer.colorMenu() when you create the menu.

Tint menu icons

There may be a better way to do this, but one option is to redraw the icon in code.

Suppose you have a menu item for favorites and want to tint it gray:

MenuItem favoriteItem = menu.findItem(R.id.action_favorite);
Drawable newIcon = (Drawable)favoriteItem.getIcon();
newIcon.mutate().setColorFilter(Color.argb(255, 200, 200, 200), PorterDuff.Mode.SRC_IN);
favoriteItem.setIcon(newIcon);

You can also use a color resource like

newIcon.mutate().setColorFilter(getResources().getColor(R.color.myCustomTint), PorterDuff.Mode.SRC_IN);

MenuItem tint for all apis - iconTint for apis 26 -

Okay, I've already found a solution.

By handling it with DrawableCompat :

 menu?.getItem(0)?.icon?.let {
DrawableCompat.setTint(
it,
ContextCompat.getColor(this, R.color.black)
)
}

Tint Navigation Icon in Toolbar

The appcompat navigation button - which is simply an AppCompatImageButton - can be styled through the toolbarNavigationButtonStyle attribute. The default style for that in the AppCompat themes is Widget.AppCompat.Toolbar.Button.Navigation, and we can extend that style to add a tint attribute value. For example:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
...

<item name="toolbarNavigationButtonStyle">@style/Toolbar.Button.Navigation.Tinted</item>

</style>

<style name="Toolbar.Button.Navigation.Tinted" parent="Widget.AppCompat.Toolbar.Button.Navigation">
<item name="tint">@color/nav_button_tint</item>
</style>

There are a couple of caveats to be aware of when using this method.

Prior to support library version 25.4.0, AppCompatImageButton did not offer its own tint attribute, and therefore a tint attribute in the app's namespace will not apply (and just won't exist, unless defined elsewhere). It is necessary to use the platform android:tint attribute if using support library version 25.3.0 or earlier.

Unfortunately, this leads to another catch, in that the platform tint prior to Lollipop (API level 21) can handle only simple, single color values, and using a ColorStateList (<selector>) resource value will cause an Exception to be thrown. This poses no problems if the android:tint value is a simple color, but it is often desired to tint the navigation icon to match another theme color attribute, which may very well be a ColorStateList. In this case, it would be necessary to create separate styles in res/values/ and res/values-21/, specifying a simple color value for android:tint in res/values/.

For example, if tinting to match the theme's primary text color:

res/values/styles.xml

<item name="android:tint">@color/normal_text_color</item>

res/values-v21/styles.xml

<item name="android:tint">?android:textColorPrimary</item>

You need only concern yourself with the notes above if you're stuck using a support library version less than 25.4.0.

Action bar menu item not tinting colour properly

Might have to do with the DrawableCompat. I always do tinting using the ColorFilter with PorterDuff, as it allows to specify exactly what type of recolouring you want (SRC_IN mostly fits the result I want to achieve)

Try to change it like this:

Drawable drawable = menu.findItem(R.id.action_info).getIcon();
drawable.setColorFilter(Color.GREEN, PorterDuff.Mode.SRC_IN);
menu.findItem(R.id.action_info).setIcon(drawable); // Actualy, we don't need to do this

EDIT:

I see. This effect is caused by the image you are using. I guess you use the default icon ic_menu_info_details which has opacity built in. It is better to use your own icon in order to color it as needed.

Basically we can take the same icon, without opacity. And then this PorterDuff method works as expected (and probably your earlier code too).

You can easily find the icon and add it to your project.

Option 1:

  • Finding the icon here: http://romannurik.github.io/AndroidAssetStudio/icons-actionbar.html

  • And add it to your drawables folder

Option 2:

  • Using vector drawables, then the images will be scaled automatically on each device too.

  • Right click on the drawable folder

  • Go to New -> Vector Asset

  • Click the change icon button, and find the Info icon

Dont forget to change your menu.xml so that you use the new icon



Related Topics



Leave a reply



Submit