Android AppCompat工具栏上的菜单项着色
当我为我的Android AppCompat工具栏上的菜单项着色,android,toolbar,android-appcompat,tint,Android,Toolbar,Android Appcompat,Tint,当我为我的工具栏菜单项使用AppCompat库中的可绘图项时,着色效果与预期一致。像这样: <item android:id="@+id/action_clear" android:icon="@drawable/abc_ic_clear_mtrl_alpha" <-- from AppCompat android:title="@string/clear" /> 在AppCompat工具栏中是否有一些特殊的魔法,只对该库中的绘图进行着色?有没有办法
工具栏
菜单项使用AppCompat
库中的可绘图项时,着色效果与预期一致。像这样:
<item
android:id="@+id/action_clear"
android:icon="@drawable/abc_ic_clear_mtrl_alpha" <-- from AppCompat
android:title="@string/clear" />
在AppCompat
工具栏
中是否有一些特殊的魔法,只对该库中的绘图进行着色?有没有办法让我自己的拖鞋也能用
在API Level 19设备上使用compileSdkVersion=21
和targetSdkVersion=21
运行此功能,并使用AppCompat
abc_ic_clear_mtrl_alpha_copy
是来自AppCompat
编辑:
着色基于我在主题中为android:textColorPrimary
设置的值
例如,#00FF00
会给我一种绿色
屏幕截图
使用AppCompat提供的可拉深材料,按预期着色
着色不适用于从AppCompat复制的drawable
因为如果您在AppCompat中查看TintManager的源代码,您将看到:
/**
* 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
};
这几乎意味着他们有特定的资源ID被列为白名单进行着色
但我想你总能看到他们是如何给这些图像着色的,并且也会这样做。在绘图设备上设置颜色过滤器非常简单。在
菜单项上设置颜色过滤器(色调)非常简单。以下是一个例子:
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);
}
如果您希望支持不同的主题,并且不希望仅仅为了颜色或透明度而有额外的副本,那么上面的代码非常有用
用于帮助器类在菜单中的所有绘图表(包括溢出图标)上设置颜色过滤器
在onCreateOptions菜单(菜单菜单菜单)
中,只需调用MenuColorizer.colorMenu(这个,菜单,颜色)代码>打开菜单后,瞧;您的图标是有色的。在新的支持库v22.1之后,您可以使用类似的功能:
@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;
}
我个人更喜欢这种方法
使用以下内容创建XML布局:
<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_action_something"
android:tint="@color/color_action_icons_tint"/>
并从您的菜单中引用此绘图:
<item
android:id="@+id/option_menu_item_something"
android:icon="@drawable/ic_action_something_tined"
这是我使用的解决方案;可以在onPrepareOptions菜单()或等效位置后调用它。mutate()的原因是如果您碰巧在多个位置使用图标;如果没有变异,它们都会呈现相同的颜色
public class MenuTintUtils {
public static void tintAllIcons(Menu menu, final int color) {
for (int i = 0; i < menu.size(); ++i) {
final MenuItem item = menu.getItem(i);
tintMenuItemIcon(color, item);
tintShareIconIfPresent(color, item);
}
}
private static void tintMenuItemIcon(int color, MenuItem item) {
final Drawable drawable = item.getIcon();
if (drawable != null) {
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
item.setIcon(drawable);
}
}
private static void tintShareIconIfPresent(int color, MenuItem item) {
if (item.getActionView() != null) {
final View actionView = item.getActionView();
final View expandActivitiesButton = actionView.findViewById(R.id.expand_activities_button);
if (expandActivitiesButton != null) {
final ImageView image = (ImageView) expandActivitiesButton.findViewById(R.id.image);
if (image != null) {
final Drawable drawable = image.getDrawable();
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
image.setImageDrawable(drawable);
}
}
}
}
}
公共类菜单{
公共静态无效色标(菜单,最终int颜色){
对于(int i=0;i
这不会处理溢出,但为此,您可以执行以下操作:
布局:
<android.support.v7.widget.Toolbar
...
android:theme="@style/myToolbarTheme" />
风格:
<style name="myToolbarTheme">
<item name="colorControlNormal">#FF0000</item>
</style>
#FF0000
这从appcompat v23.1.0开始生效。此线程中的大多数解决方案要么使用较新的API,要么使用反射,要么使用强化视图查找来访问扩展的菜单项
然而,有一种更优雅的方法可以做到这一点。您需要一个自定义工具栏,因为您的“应用自定义色调”用例不能很好地使用公共样式/主题API
public class MyToolbar extends Toolbar {
... some constructors, extracting mAccentColor from AttrSet, etc
@Override
public void inflateMenu(@MenuRes int resId) {
super.inflateMenu(resId);
Menu menu = getMenu();
for (int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
Drawable icon = item.getIcon();
if (icon != null) {
item.setIcon(applyTint(icon));
}
}
}
void applyTint(Drawable icon){
icon.setColorFilter(
new PorterDuffColorFilter(mAccentColor, PorterDuff.Mode.SRC_IN)
);
}
}
没有反射,没有视图查找,也没有那么多代码,嗯
现在,您可以忽略可笑的onCreateOptions菜单/onOptions项Selected
app:icontent
属性在支持库的SupportMenuInflater
中实现(至少在28.0.0中)
使用API 15及以上标准成功测试
菜单资源文件:
<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>
这对我很有用:
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.player_menu, menu)
//tinting menu item:
val typedArray = theme.obtainStyledAttributes(IntArray(1) { android.R.attr.textColorSecondary })
val textColor = typedArray.getColor(0, 0)
typedArray.recycle()
val item = menu?.findItem(R.id.action_chapters)
val icon = item?.icon
icon?.setColorFilter(textColor, PorterDuff.Mode.SRC_IN);
item?.icon = icon
return true
}
也可以在可绘制xml中使用色调:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:textColorSecondary"
android:viewportWidth="384"
android:viewportHeight="384">
<path
android:fillColor="#FF000000"
android:pathData="M0,277.333h384v42.667h-384z" />
<path
android:fillColor="#FF000000"
android:pathData="M0,170.667h384v42.667h-384z" />
<path
android:fillColor="#FF000000"
android:pathData="M0,64h384v42.667h-384z" />
</vector>
两种样式是否具有相同的父样式?如果您用自己的样式扩展顶级样式会怎么样?样式没有区别。唯一的区别是可绘制文件,它们都是.png文件。可绘制文件看起来像是代码中原始可绘制文件的精确副本?它们是我复制的png文件。它们是完全相同的。那么,如果你的代码具有相同的样式和相同的图像,那么你的代码与原始代码有什么不同呢?啊,这就是我害怕的。我没有在SDK中找到AppCompat的源代码,这就是为什么我自己没有找到这部分。我想那我就得在Google Source.com上浏览了。谢谢我知道这是一个无关紧要的问题,但为什么会有白名单?如果它可以用这些图标着色,那么为什么我们不能给自己的图标着色呢?另外,当你忽略了一件最重要的事情时,让几乎所有东西都向后兼容(与AppCompat兼容)有什么意义呢:有动作栏图标(带有自定义颜色)。谷歌的问题跟踪器中有一个问题已经解决了
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.player_menu, menu)
//tinting menu item:
val typedArray = theme.obtainStyledAttributes(IntArray(1) { android.R.attr.textColorSecondary })
val textColor = typedArray.getColor(0, 0)
typedArray.recycle()
val item = menu?.findItem(R.id.action_chapters)
val icon = item?.icon
icon?.setColorFilter(textColor, PorterDuff.Mode.SRC_IN);
item?.icon = icon
return true
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:textColorSecondary"
android:viewportWidth="384"
android:viewportHeight="384">
<path
android:fillColor="#FF000000"
android:pathData="M0,277.333h384v42.667h-384z" />
<path
android:fillColor="#FF000000"
android:pathData="M0,170.667h384v42.667h-384z" />
<path
android:fillColor="#FF000000"
android:pathData="M0,64h384v42.667h-384z" />
</vector>