Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/202.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android AppCompat工具栏上的菜单项着色_Android_Toolbar_Android Appcompat_Tint - Fatal编程技术网

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>