MenuItem kleuren op AppCompat Toolbar

Als ik tekenbestanden uit de AppCompat-bibliotheek gebruik voor mijn Toolbar-menu-items, werkt de tinting zoals verwacht. Zoals dit:

<item
    android:id="@+id/action_clear"
    android:icon="@drawable/abc_ic_clear_mtrl_alpha"  <-- from AppCompat
    android:title="@string/clear" />

Maar als ik mijn eigen drawables gebruik of zelfs de drawables uit de AppCompat-bibliotheek naar mijn eigen project kopieer, wordt het helemaal niet getint.

<item
    android:id="@+id/action_clear"
    android:icon="@drawable/abc_ic_clear_mtrl_alpha_copy"  <-- copy from AppCompat
    android:title="@string/clear" />

Is er een speciale magie in de AppCompatToolbardie alleen tekenbare items uit die bibliotheek kleurt? Is er een manier om dit te laten werken met mijn eigen drawables?

Dit uitvoeren op een API Level 19-apparaat met compileSdkVersion = 21en targetSdkVersion = 21, en ook alles gebruiken van AppCompat

abc_ic_clear_mtrl_alpha_copyis een exacte kopie van de abc_ic_clear_mtrl_alphapng van AppCompat

Bewerken:

De tint is gebaseerd op de waarde die ik heb ingesteld voor android:textColorPrimaryin mijn thema.

Bijvoorbeeld <item name="android:textColorPrimary">#00FF00</item>zou me een groene tint geven.

Schermafbeeldingen

Het kleuren werkt zoals verwacht met tekenbaar van AppCompat
Tint werkt zoals verwacht met tekenbaar van AppCompat

Tint werkt niet met tekenbaar gekopieerd van AppCompat
Tint werkt niet met tekenbaar gekopieerd van AppCompat


Antwoord 1, autoriteit 100%

Na de nieuwe ondersteuningsbibliotheek v22.1 kunt u iets soortgelijks als dit gebruiken:

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

Antwoord 2, autoriteit 84%

Het instellen van een ColorFilter(tint) op een MenuItemis eenvoudig. Hier is een voorbeeld:

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

De bovenstaande code is erg handig als je verschillende thema’s wilt ondersteunen en je geen extra exemplaren wilt hebben alleen voor de kleur of transparantie.

Klik hiervoor een hulpklasse om een ​​ColorFilterop alle tekenbare objecten in een menu, inclusief het overlooppictogram.

In onCreateOptionsMenu(Menu menu)bel je gewoon MenuColorizer.colorMenu(this, menu, color);na het opblazen van je menu en voila; je pictogrammen zijn getint.


Antwoord 3, autoriteit 78%

Het kenmerk

app:iconTintis geïmplementeerd in SupportMenuInflatervanuit de ondersteuningsbibliotheek (tenminste in 28.0.0).

Succesvol getest met API 15 en hoger.

Menubronbestand:

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

(In dit geval was ?attr/appIconColorEnabledeen aangepast kleurkenmerk in de thema’s van de app en waren de pictogrambronnen vectortekens.)


Antwoord 4, autoriteit 31%

Want als je de broncode van de TintManager in AppCompat bekijkt, zie je:

/**
 * 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
};

Wat vrijwel betekent dat ze bepaalde resourceIds op de witte lijst hebben staan ​​om getint te worden.

Maar ik denk dat je altijd kunt zien hoe ze die afbeeldingen kleuren en hetzelfde doen. Het is net zo eenvoudig als het ColorFilter op een tekenbaar bestand zetten.


Antwoord 5, autoriteit 30%

Ik heb persoonlijk de voorkeur gegeven aan deze benadering van deze link

Maak een XML-layout met het volgende:

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

en verwijs naar deze tekenbare uit je menu:

<item
    android:id="@+id/option_menu_item_something"
    android:icon="@drawable/ic_action_something_tined"

Antwoord 6, autoriteit 11%

De meeste oplossingen in deze thread gebruiken ofwel een nieuwere API, of gebruiken reflectie, of gebruiken intensieve zoekacties om bij het opgeblazen MenuItemte komen.

Er is echter een elegantere manier om dat te doen. U hebt een aangepaste werkbalk nodig, omdat uw gebruiksscenario voor ‘aangepaste tint toepassen’ niet goed samengaat met de openbare API voor styling/thema’s.

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

Zorg ervoor dat u uw activiteit-/fragmentcode inbelt:

toolbar.inflateMenu(R.menu.some_menu);
toolbar.setOnMenuItemClickListener(someListener);

Geen reflectie, geen lookup, en niet zo veel code, hè?

En nu kun je het belachelijke onCreateOptionsMenu/onOptionsItemSelectednegeren.

Other episodes