
[英]AppCompat ToolBar popupTheme not used in the ShareAction MenuItem
[英]MenuItem tinting on AppCompat Toolbar
当我将AppCompat
库中的可绘制对象用于我的Toolbar
菜单项时,着色按预期工作。 像这样:
<item
android:id="@+id/action_clear"
android:icon="@drawable/abc_ic_clear_mtrl_alpha" <-- from AppCompat
android:title="@string/clear" />
但是,如果我使用自己的可绘制对象,或者实际上甚至将可绘制对象从AppCompat
库复制到我自己的项目中,它根本不会着色。
<item
android:id="@+id/action_clear"
android:icon="@drawable/abc_ic_clear_mtrl_alpha_copy" <-- copy from AppCompat
android:title="@string/clear" />
AppCompat
Toolbar
是否有一些特殊的魔法只为该库中的可绘制对象着色? 有什么办法可以让它与我自己的可绘制对象一起使用?
在compileSdkVersion = 21
和targetSdkVersion = 21
API 级别 19 设备上运行它,并且还使用AppCompat
所有内容
abc_ic_clear_mtrl_alpha_copy
是来自AppCompat
的abc_ic_clear_mtrl_alpha
png 的精确副本
编辑:
着色基于我在主题中为android:textColorPrimary
设置的值。
例如<item name="android:textColorPrimary">#00FF00</item>
会给我一个绿色的色调。
截图
使用 AppCompat 中的 drawable 进行着色按预期工作
着色不适用于从 AppCompat 复制的可绘制对象
在新的支持库 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;
}
在MenuItem
上设置ColorFilter
(色调)很简单。 下面是一个例子:
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);
}
如果您想支持不同的主题并且不想只为颜色或透明度而有额外的副本,则上述代码非常有用。
单击此处获取帮助程序类以在菜单中的所有可绘制对象上设置ColorFilter
,包括溢出图标。
在onCreateOptionsMenu(Menu menu)
只需调用MenuColorizer.colorMenu(this, menu, color);
在给你的菜单充气之后,瞧; 你的图标是有色的。
app:iconTint
属性在支持库中的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>
(在这种情况下?attr/appIconColorEnabled
是应用程序主题中的自定义颜色属性,图标资源是矢量可绘制对象。)
因为如果你看一下 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
};
这几乎意味着他们将特定的 resourceIds 列入白名单以进行着色。
但我想你总能看到他们如何给这些图像着色并做同样的事情。 就像在可绘制对象上设置 ColorFilter 一样简单。
我个人更喜欢这个链接中的这种方法
使用以下内容创建 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"
该线程中的大多数解决方案要么使用较新的 API,要么使用反射,或者使用密集的视图查找来获取膨胀的MenuItem
。
但是,有一种更优雅的方法可以做到这一点。 您需要一个自定义工具栏,因为您的“应用自定义色调”用例不能很好地与公共样式/主题 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)
);
}
}
只要确保你调用了你的 Activity/Fragment 代码:
toolbar.inflateMenu(R.menu.some_menu);
toolbar.setOnMenuItemClickListener(someListener);
没有反射,没有视图查找,也没有那么多代码,是吧?
现在你可以忽略荒谬的onCreateOptionsMenu/onOptionsItemSelected
。
这是我使用的解决方案; 您可以在 onPrepareOptionsMenu() 或等效位置之后调用它。 mutate() 的原因是如果你碰巧在多个位置使用图标; 如果没有 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);
}
}
}
}
}
这不会处理溢出,但为此,您可以这样做:
布局:
<android.support.v7.widget.Toolbar
...
android:theme="@style/myToolbarTheme" />
款式:
<style name="myToolbarTheme">
<item name="colorControlNormal">#FF0000</item>
</style>
这适用于 appcompat v23.1.0。
这对我有用:
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 中使用 tint:
<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>
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_home, menu);
//One item tint
menu.get(itemId).getIcon().setTint(Color);
//or all
for(int i=0;i<menu.size();i++){
menu.get(i).getIcon().setTint(Color);
}
return true;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.