可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I've noticed that using AppCompat themes, default toolbar icons get tinted by the attribute colorControlNormal
in my style.
<style name="MyTheme" parent="Theme.AppCompat">
<item name="colorControlNormal">@color/yellow</item>
</style>
As you can see above, however, it does not happen with all icons. I provided the "plus" sign, which I got from the official icons, and it does not get tinted (I used the "white" version of the png). From what I have understood from this question, system tints only icons with just an alpha channel. Is this true?
If so: Is there a place where I can find alpha-defined, official material icons? If not - and if Toolbar icons need to be alpha-only to be tinted - how is Google expecting us to use provided icons in a Toolbar?
Somewhere in the SDK I found some icons ending in _alpha.png
, and they actually get tinted well. However I need the full set of material icons, and from the official sources I could only find white
, grey600
and black
ones.
Applying a ColorFilter
at runtime would be slightly painful, and my actual Toolbar - with some icons tinted, some others not - looks quite bad.
回答1:
Another option is to use the new support for vector drawables in the support library.
See res/xml/ic_search.xml
in blog post AppCompat — Age of the vectors
Notice the reference to ?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>
回答2:
Here is the solution that I use. Call tintAllIcons after onPrepareOptionsMenu or the equivalent location. The reason for mutate() is if you happen to use the icons in more than one location; without the mutate, they will all take on the same tint.
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);
}
}
}
}
}
This won't take care of the overflow, but for that, you can do this:
Layout:
<android.support.v7.widget.Toolbar
...
android:theme="@style/myToolbarTheme" />
Styles:
<style name="myToolbarTheme">
<item name="colorControlNormal">#FF0000</item>
</style>
This works as of appcompat v23.1.0.
回答3:
I actually was able to do this on API 10 (Gingerbread) and it worked very well.
Edit: It worked on API 22 also...
Here's the final result.
Note: The icon is a drawable resource in the drawable folder(s).
Now here's how its done:
@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);
}
At this point you can change it to any color you want!
回答4:
I see this question is getting some views so I'm going to post an answer for those who don't read the comments.
My conjectures in the question were all wrong and it is not a matter of alpha channels, at least not externally. The fact is simply that, quoting @alanv ,
AppCompat only tints its own icons. For now, you will need to manually
tint any icons that you're providing separately from AppCompat.
This might change in the future but also might not. From this answer you can also see the list of icons (they all belong to the internal resource folder of appcompat, so you can't change them) that are automatically tinted and with which color.
Personally I use a colorControlNormal
which is black or white (or similar shades), and import the icons with that particular color. Colored icons on a colored background look a little bad. However, another solution I found pleasant is this class on github. You just call MenuColorizer.colorMenu()
when you create the menu.
回答5:
You could just create a custom Toolbar that uses your tint color when inflating the menu.
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)
);
}
}
Just make sure you call in your Activity/Fragment code:
toolbar.inflateMenu(R.menu.some_menu);
toolbar.setOnMenuItemClickListener(someListener);
No reflection, no view lookup, and not so much code, huh?
And don't use onCreateOptionsMenu/onOptionsItemSelected
, if you use this approach
回答6:
For sdk 23 or higher:
<style name="AppThemeToolbar" parent="MyAppTheme">
....
<item name="android:drawableTint">@color/secondaryLightColor</item>
</style>
My toolbar
<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>
回答7:
That's the final and true answer
First create style for toolbar like this:
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" >
<item name="iconTint">@color/primaryTextColor</item>
<!--choice your favorite color-->
</style>
Then in your main app or activity them add this line
<item name="actionBarPopupTheme">@style/AppTheme.PopupOverlay</item>
And finally in you layout file add this line to your toolbar
android:theme="?attr/actionBarPopupTheme"
And Then you will see your toolbar icons colored in your favorite color
回答8:
@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;
}
and call in this manner:
MenuItem location = menu.findItem(R.id.action_location);
DrawableUtils.setTintDrawable(location.getIcon(), Color.WHITE);