Android 上的工具栏图标着色

49

我注意到使用AppCompat主题时,我的样式中的默认工具栏图标会被属性colorControlNormal着色。

<style name="MyTheme" parent="Theme.AppCompat">
    <item name="colorControlNormal">@color/yellow</item>
</style>

在这里输入图片描述

如上所示,但不是所有图标都会发生这种情况。我提供了“加号”符号,这个符号我从官方图标中获取的,但它没有被着色(我使用了png的“白色”版本)。根据我从这个问题了解到的,系统只为仅具有 alpha 通道的图标进行着色。这是真的吗?

如果是这样的话:是否有一个地方可以找到官方的 alpha 设计的 material icons?如果不是 - 如果 Toolbar 图标需要是 alpha-only 才能着色 - 那 Google 是如何希望我们在 Toolbar 中使用提供的图标呢?

在 SDK 的某个地方,我找到了一些以 _alpha.png 结尾的图标,并且它们着色得很好。然而,我需要完整的 material icons 集合,在官方资源中我只能找到白色灰色600黑色的图标。

在运行时应用 ColorFilter 将会有些麻烦,而我的实际 Toolbar - 有些图标着色,有些图标没有着色 - 看起来相当糟糕。


2
AppCompat 只会给自己的图标着色。目前,您需要手动为与 AppCompat 分开提供的任何图标进行着色。 - alanv
另外,链接的问题仅适用于通知,而不是一般的着色。 - alanv
1
请参考这篇StackO-Post进行详细解释。 - reVerse
看来我应该再搜索一会儿。 我很乐意接受你的答案@alanv,或者让我们将其标记为重复项。 出于好奇,您是否说“目前”是因为您知道即将推出修复程序,还是仅仅是你的想象? - natario
这是我们想做的事情,但我不能做出任何承诺。 - alanv
12个回答

40

另一个选择是使用支持库中对矢量可绘制对象的新支持。

请参阅博客文章AppCompat - 矢量时代中的res/xml/ic_search.xml

注意引用了?attr/colorControlNormal

<vector xmlns:android="..."
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0"
    android:tint="?attr/colorControlNormal">
    <path
        android:pathData="..."
        android:fillColor="@android:color/white"/>
</vector>

在使用android:tintandroid:fillColor属性时,使用?attr/colorControlNormal有什么区别?谢谢! - Thomas Vos
@SuperThomasLab 这个例子来自 Chris Banes 的博客,其中演示了如何用着色的矢量图替换着色的图片。请注意,fillColor 在源图像中被硬编码了。我不知道 AppCompat 是否支持其他颜色表示方式。 - Joe Bowbeer
我寻找这个答案已经很久了。非常感谢。 - S. Gissel

23

这是我使用的解决方案。在onPrepareOptionsMenu或等效位置之后调用tintAllIcons函数。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 版本,此方法有效。


17

我实际上能够在API 10(姜饼)上完成此操作,并且它运行得非常好。

编辑:它在API 22上也可以运行...

这是最终结果。

输入图像描述

注意:该图标是drawable文件夹中的可绘制资源。

现在,这就是如何完成它的:

@Override
public void onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);

    MenuItem item = menu.findItem(R.id.action_refresh);
    Drawable icon = getResources().getDrawable(R.drawable.ic_refresh_white_24dp);
    icon.setColorFilter(getResources().getColor(R.color.colorAccent), PorterDuff.Mode.SRC_IN);

    item.setIcon(icon);
}

此时,您可以将其更改为任何您想要的颜色!


16

那就是最终而真实的答案。首先,创建工具栏的样式如下:

  <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" >
     <item name="iconTint">@color/primaryTextColor</item>
    <!--choice your favorite color-->
  </style>

然后在你的主应用程序或活动主题中添加这一行

  <item name="actionBarPopupTheme">@style/AppTheme.PopupOverlay</item>

最后,在您的布局文件中,将此行添加到工具栏中。

 android:theme="?attr/actionBarPopupTheme"

然后你会看到你的工具栏图标变成了你喜欢的颜色。


6

针对sdk 23或更高版本:

<style name="AppThemeToolbar" parent="MyAppTheme">
        ....
        <item name="android:drawableTint">@color/secondaryLightColor</item>
    </style>


    <com.google.android.material.appbar.AppBarLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content">
      <androidx.appcompat.widget.Toolbar
          android:theme="@style/AppThemeToolbar"
          android:layout_width="match_parent"
          android:layout_height="attr/actionBarSize">
      </androidx.appcompat.widget.Toolbar>
    </com.google.android.material.appbar.AppBarLayout>


6

我看到这个问题引起了一些关注,所以我想给那些不读评论的人发表一个答案。

在我的问题猜测中,所有都是错误的,并不是alpha通道的问题,至少不是外部的。事实上,引用@alanv的话说:

AppCompat只会给自己的图标着色。目前,您需要手动调整任何与AppCompat分开提供的图标的色彩。

这可能会在未来发生变化,也可能不会。从这个答案中,您还可以看到被自动着色并带有颜色的图标列表(它们都属于appcompat的内部资源文件夹,因此您无法更改它们)。

个人建议使用colorControlNormal,颜色为黑色或白色(或类似色调),并且导入具有特定颜色的图标。彩色图标在彩色背景上看起来有点糟糕。但是,我发现另一个令人愉悦的解决方案是这个类,在创建菜单时只需调用MenuColorizer.colorMenu()即可。


似乎Java类已经被更改。 - San Juan

5

您可以创建一个自定义工具栏,当填充菜单时使用您的色调颜色。

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


1
使用androidX,您可以像这样定义工具栏:
<androidx.appcompat.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:theme="@style/Toolbar" />

然后,扩展一个AppCompat主题并根据您的喜好设置colorControlNormal属性:

<style name="Toolbar" parent="Theme.AppCompat.Light">
    <item name="colorControlNormal">@color/colorBaseWhite</item>
    <item name="android:background">@color/colorPrimary</item>
</style>

关键在于为工具栏指定主题,这样您就可以使用“?attr/”引用来设置颜色。 - Daniel Jette

1
这可以使用 Kotlin 实现:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    menu.getItem(0)?.icon?.setTint(Color.WHITE)
}
else {
    @Suppress("DEPRECATION")
    menu.getItem(0)?.icon?.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)
}

它应该适用于所有现代版本的Android,如果getItemicon返回null,则会失败而不崩溃。

1
尝试这个...
  menu.getItem(0).getIcon().setTint(Color.parseColor("#22CC34"));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接