Android 上的工具栏图标着色

Posted

技术标签:

【中文标题】Android 上的工具栏图标着色【英文标题】:Toolbar icon tinting on Android 【发布时间】:2015-03-28 22:36:56 【问题描述】:

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

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

但是,正如您在上面看到的,并非所有图标都会发生这种情况。我提供了从官方图标中获得的“加号”符号,它没有着色(我使用了 png 的“白色”版本)。根据我从question 中了解到的情况,系统仅对带有 Alpha 通道的图标进行着色。这是真的吗?

如果是这样:有没有可以找到 alpha 定义的官方材料图标的地方?如果不是 - 并且如果工具栏图标需要仅 alpha 进行着色 - Google 如何期望我们在工具栏中使用提供的图标?

在 SDK 的某个地方,我发现了一些以 _alpha.png 结尾的图标,它们的颜色实际上很好。但是我需要全套素材图标,从官方来源我只能找到whitegrey600black

在运行时应用 ColorFilter 会有点痛苦,而我的实际工具栏 - 有些图标有色,有些没有 - 看起来很糟糕。

【问题讨论】:

AppCompat 只为自己的图标着色。目前,您需要手动为您单独提供的任何图标着色,而不是 AppCompat。 另外,链接的问题仅适用于通知,不适用于一般着色。 详细解释请参见this StackO-Post。 看来我应该搜索更长的时间。我很乐意接受您的回答@alanv,或者我们将其标记为重复。出于好奇,您确实会说“暂时”,因为您知道即将进行修复,或者您只是想象一下? 这是我们想做的事情,但我不能做出任何承诺。 【参考方案1】:

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

请参阅博文AppCompat — Age of the vectors中的res/xml/ic_search.xml

注意对?attr/colorControlNormal的引用

<vector xmlns:android="..."
    android:
    android:
    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 有什么区别?谢谢! @SuperThomasLab 该示例来自 Chris Banes 的博客,其中说明了用着色矢量替换着色图像。请注意,fillColor 在源图像中被有效地硬编码。我不知道 AppCompat 现在是否支持其他颜色表示。【参考方案2】:

这是我使用的解决方案。在 onPrepareOptionsMenu 或等效位置之后调用 tintAllIcons。 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。

【讨论】:

【参考方案3】:

我实际上能够在 API 10 (Gingerbread) 上做到这一点,而且效果很好。

编辑:它也适用于 API 22...

这是最终结果。

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

下面是它的完成方式:

@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);

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

【讨论】:

【参考方案4】:

这是最终的真实答案 首先为工具栏创建样式,如下所示:

  <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"

然后您会看到工具栏图标以您喜欢的颜色着色

【讨论】:

【参考方案5】:

我看到这个问题正在获得一些观点,所以我将为那些不阅读 cmets 的人发布答案。

我在问题中的猜想都是错误的,这不是 Alpha 通道的问题,至少不是外部的。事实很简单,引用@alanv,

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

这在未来可能会改变,但也可能不会。从this answer你还可以看到自动着色的图标列表(它们都属于appcompat的内部资源文件夹,所以你不能更改它们)。

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

【讨论】:

java类好像变了【参考方案6】:

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

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

【讨论】:

【参考方案7】:

对于 sdk 23 或更高版本:

<style name="AppThemeToolbar" parent="MyAppTheme">
        ....
        <item name="android:drawableTint">@color/secondaryLightColor</item>
    </style>
我的工具栏

    <com.google.android.material.appbar.AppBarLayout
      android:layout_
      android:layout_>
      <androidx.appcompat.widget.Toolbar
          android:theme="@style/AppThemeToolbar"
          android:layout_
          android:layout_>
      </androidx.appcompat.widget.Toolbar>
    </com.google.android.material.appbar.AppBarLayout>

【讨论】:

【参考方案8】:

使用 androidX,您可以像这样定义您的工具栏

<androidx.appcompat.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_
    android:layout_
    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/ 引用作为您的颜色。【参考方案9】:

这可以通过以下方式在 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,它将失败而不会崩溃。

【讨论】:

【参考方案10】:

试试这个...?

  menu.getItem(0).getIcon().setTint(Color.parseColor("#22CC34"));

【讨论】:

【参考方案11】:
@NonNull
public static Drawable setTintDrawable(@NonNull Drawable drawable, @ColorInt int color) 
   drawable.clearColorFilter();
   drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
   drawable.invalidateSelf();
   Drawable wrapDrawable = DrawableCompat.wrap(drawable).mutate();
   DrawableCompat.setTint(wrapDrawable, color);
   return wrapDrawable;
 

并以这种方式调用:

MenuItem location = menu.findItem(R.id.action_location);
DrawableUtils.setTintDrawable(location.getIcon(), Color.WHITE);

【讨论】:

【参考方案12】:

基本上,当您设置菜单时,三点图标会从 AppTheme 中获取 android:textColorSecondary 的颜色,默认设置为黑色。

因此,如果您没有在项目中的任何位置使用 textColorSecondary,那么您只需添加以下行

<item name="android:textColorSecondary">@color/White</item>

添加后可能如下所示。

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    <!-- Customise your theme here. -->

    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:textColorSecondary">@color/White</item>
</style>

【讨论】:

以上是关于Android 上的工具栏图标着色的主要内容,如果未能解决你的问题,请参考以下文章

在溢出菜单和子菜单中为菜单图标着色

小工具固定大小的图标Android

工具栏导航汉堡图标丢失

更改 SearchView 上的工具栏颜色/样式单击

如何更改Android中的汉堡包图标(导航抽屉)

使用Android的新工具栏图标被切断