MenuItem tinting on AppCompat Toolbar
app:iconTint
attribute is implemented in SupportMenuInflater
from the support library (at least in 28.0.0).
Tested successfully with API 15 and up.
Menu resource file:
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_settings"
android:icon="@drawable/ic_settings_white_24dp"
app:iconTint="?attr/appIconColorEnabled" <!-- using app name space instead of android -->
android:menuCategory="system"
android:orderInCategory="1"
android:title="@string/menu_settings"
app:showAsAction="never"
/>
<item
android:id="@+id/menu_themes"
android:icon="@drawable/ic_palette_white_24dp"
app:iconTint="?attr/appIconColorEnabled"
android:menuCategory="system"
android:orderInCategory="2"
android:title="@string/menu_themes"
app:showAsAction="never"
/>
<item
android:id="@+id/action_help"
android:icon="@drawable/ic_help_white_24dp"
app:iconTint="?attr/appIconColorEnabled"
android:menuCategory="system"
android:orderInCategory="3"
android:title="@string/menu_help"
app:showAsAction="never"
/>
</menu>
(In this case ?attr/appIconColorEnabled
was a custom color attribute in the app's themes, and the icon resources were vector drawables.)
After the new Support library v22.1, you can use something similar to this:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_home, menu);
Drawable drawable = menu.findItem(R.id.action_clear).getIcon();
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(drawable, ContextCompat.getColor(this,R.color.textColorPrimary));
menu.findItem(R.id.action_clear).setIcon(drawable);
return true;
}
Setting a ColorFilter
(tint) on a MenuItem
is simple. Here is an example:
Drawable drawable = menuItem.getIcon();
if (drawable != null) {
// If we don't mutate the drawable, then all drawable's with this id will have a color
// filter applied to it.
drawable.mutate();
drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
drawable.setAlpha(alpha);
}
The above code is very helpful if you want to support different themes and you don't want to have extra copies just for the color or transparency.
Click here for a helper class to set a ColorFilter
on all the drawables in a menu, including the overflow icon.
In onCreateOptionsMenu(Menu menu)
just call MenuColorizer.colorMenu(this, menu, color);
after inflating your menu and voila; your icons are tinted.
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.