AppCompat टूलबार पर MenuItem टिनिंग


93

जब मैं AppCompatअपने Toolbarमेनू आइटम के लिए लाइब्रेरी से ड्रॉबल्स का उपयोग करता हूं , तो टिनटिंग अपेक्षा के अनुरूप काम करता है। ऐशे ही:

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

लेकिन अगर मैं अपने स्वयं के ड्रॉबल्स का उपयोग करता हूं या वास्तव में AppCompatलाइब्रेरी से ड्रॉबल्स को अपने स्वयं के प्रोजेक्ट में कॉपी करता हूं तो यह बिल्कुल भी टिंट नहीं होगा।

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

क्या AppCompat Toolbarउस लाइब्रेरी से केवल टिंट ड्रॉबल्स में कुछ विशेष जादू है ? किसी भी तरह से इसे पाने के लिए अपने स्वयं के ड्रॉबल्स के साथ काम करने के लिए?

यह एपीआई स्तर 19 डिवाइस पर चल रहा है compileSdkVersion = 21और इसके साथ ही targetSdkVersion = 21सब कुछ का उपयोग कर रहा हैAppCompat

abc_ic_clear_mtrl_alpha_copyabc_ic_clear_mtrl_alphaसे png की एक सटीक प्रति हैAppCompat

संपादित करें:

टिनटिंग android:textColorPrimaryमेरे विषय में मेरे द्वारा निर्धारित मूल्य पर आधारित है ।

उदा <item name="android:textColorPrimary">#00FF00</item>मुझे हरे रंग का रंग देता।

स्क्रीनशॉट

AppCompat से drawable के साथ उम्मीद के मुताबिक काम करने वाली टिनिंग AppCompat से drawable के साथ उम्मीद के मुताबिक काम करने वाली टिनिंग

AppCompat से कॉपी किए गए ड्रॉएबल के साथ काम नहीं कर रहा टिनिंग AppCompat से कॉपी किए गए ड्रॉएबल के साथ काम नहीं कर रहा टिनिंग


दोनों शैलियों में एक ही माता-पिता हैं? क्या होगा यदि आप अपने स्वयं के साथ शीर्ष शैली का विस्तार करते हैं?
G_V

शैलियों में कोई अंतर नहीं है। एकमात्र अंतर
ड्रॉबल है

कोड में ड्रा करने योग्य मूल AppCombat की सटीक प्रतिलिपि जैसा दिखता है?
G_V

वे पीएनजी फाइलें हैं, जिन्हें मैंने कॉपी किया था। वे बिलकुल एक जैसे हैं।
13

तो जहां वास्तव में आपका कोड मूल से भिन्न होता है अगर उसमें समान शैली और समान छवि है?
G_V

जवाबों:


31

क्योंकि यदि आप 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
};

जो बहुत ज्यादा मतलब है कि वे विशेष संसाधन है सफेद रंगा हुआ होने के लिए।

लेकिन मुझे लगता है कि आप हमेशा देख सकते हैं कि वे उन छवियों को कैसे चिन्हित कर रहे हैं और वही करते हैं। यह उतना ही आसान है जितना कि कलरफिल्टर को एक ड्रॉबल पर सेट करना।


उह, यही मैं डरता था। मुझे SDK में AppCompat के लिए सोर्स कोड नहीं मिला, इसीलिए मुझे यह हिस्सा खुद नहीं मिला। मुझे लगता है कि मुझे googlesource.com पर ब्राउज़ करना होगा। धन्यवाद!
ग्रेवे ने

8
मुझे पता है कि यह एक पेचीदा सवाल है लेकिन एक सफेद सूची क्यों है? यदि यह इन आइकनों के साथ टिनटिंग कर सकता है तो हम अपने आइकनों को टिंट क्यों नहीं कर सकते हैं? साथ ही, लगभग हर चीज को बैकवर्ड संगत (AppCompat के साथ) बनाने में क्या बात है जब आप सबसे महत्वपूर्ण चीज में से एक को छोड़ देते हैं: एक्शन बार आइकन (कस्टम रंग के साथ)।
Zsolt Safrany

1
वहाँ गूगल की समस्या ट्रैकर में यह तय हो गई के रूप में चिह्नित किया गया है कि के लिए एक मुद्दा है, लेकिन यह मेरे लिए काम नहीं है, लेकिन आप इसे यहाँ ट्रैक कर सकते हैं: issuetracker.google.com/issues/37127128
niknetniko

उनका दावा है कि यह तय है, लेकिन ऐसा नहीं है। गोश, मैं एंड्रॉइड थीम इंजन, AppCompat और इसके साथ जुड़े सभी बकवास। यह केवल "जीथब रेपो ब्राउज़र" नमूना ऐप्स के लिए काम करता है।
मार्टिन मार्कोसिनी

97

नई समर्थन लाइब्रेरी 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;
    }

1
मैं कहूंगा कि इस मामले में पुराना setColorFilter()तरीका बेहतर है।
नैटारियो

@mvai, क्यों setColorFilter () अधिक प्रचलित है?
वन्यदेव

4
@ गिल्डदेव संक्षिप्त जब आप menu.findItem ()। GetIcon ()। SetColorFilter () पर जा सकते हैं, तो DrawableCompat वर्ग को क्यों परेशान करें? एक लाइनर और स्पष्ट।
नटारियो

4
जब आप अपने स्वयं के TintingUtils.tintMenuIcon (...) विधि या जो कुछ भी आप इसे कॉल करना चाहते हैं, उसमें एक-लाइनर तर्क अप्रासंगिक है। यदि आपको भविष्य में तर्क को बदलने या समायोजित करने की आवश्यकता है, तो आप इसे एक ही स्थान पर करते हैं, सभी अनुप्रयोग पर नहीं।
दान डार 3

1
यह कमाल का है!
तेजस्वी इस्लाम

82

ColorFilter(टिंट) को एक पर सेट करना MenuItemसरल है। यहाँ एक उदाहरण है:

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

उपरोक्त कोड बहुत उपयोगी है यदि आप विभिन्न विषयों का समर्थन करना चाहते हैं और आप रंग या पारदर्शिता के लिए अतिरिक्त प्रतियां नहीं चाहते हैं।

ColorFilterअतिप्रवाह आइकन सहित मेनू में सभी ड्रॉबल्स परसेट करने के लिए एक सहायक वर्ग के लिए यहां क्लिक करें

में onCreateOptionsMenu(Menu menu)सिर्फ कॉल MenuColorizer.colorMenu(this, menu, color);अपने मेनू और देखा बढ़ा-चढ़ाकर के बाद; आपके आइकन टिंटेड हैं।


धन्यवाद, निश्चित रूप से कोशिश करेंगे कि बाहर!
ग्रेव

3
मैं अपने डेस्क के खिलाफ अपने सिर को पीटने की कोशिश कर रहा हूं, यह जानने की कोशिश कर रहा हूं कि मेरे सभी आइकन क्यों टिंट किए जा रहे हैं, ड्रॉबलमाउटेट () के बारे में सिर के लिए धन्यवाद!
स्कॉट कूपर

49

app:iconTintSupportMenuInflaterसमर्थन लाइब्रेरी (कम से कम 28.0.0 में) से विशेषता कार्यान्वित की जाती है।

एपीआई 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>

(इस मामले ?attr/appIconColorEnabledमें ऐप के थीम में एक कस्टम रंग विशेषता थी, और आइकन संसाधन वेक्टर ड्रॉबल थे।)


5
यह नया स्वीकृत उत्तर होना चाहिए! इसके अलावा, कृपया ध्यान दें android:iconTintऔर android:iconTintModeकाम न करें, लेकिन एक आकर्षण की तरह काम app:करने के बजाय उपसर्ग करना android:(मेरे अपने सदिश आरेखों पर, एपीआई> = 21)
सेबेस्टियन अल्वारेज़ रोड्रिगेज

यदि प्रोग्रामेटिक रूप से कॉलिंग: ध्यान दें कि SupportMenuInflaterकोई भी कस्टम तर्क लागू नहीं होगा यदि मेनू एक SupportMenuजैसा नहीं है MenuBuilder, तो यह नियमित रूप से वापस आ जाता है MenuInflater
21

इस मामले में, उपयोग AppCompatActivity.startSupportActionMode(callback)और उपयुक्त समर्थन कार्यान्वयन से androidx.appcompatकॉलबैक में पारित किया जाएगा।
गीकले

30

मैंने व्यक्तिगत रूप से इस लिंक से इस दृष्टिकोण को प्राथमिकता दी

निम्नलिखित के साथ एक 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"/>

और अपने मेनू से इस drawable को देखें:

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

2
हालांकि यह लिंक प्रश्न का उत्तर दे सकता है, लेकिन उत्तर के आवश्यक हिस्सों को यहां शामिल करना और संदर्भ के लिए लिंक प्रदान करना बेहतर है। लिंक-केवल उत्तर अमान्य हो सकते हैं यदि लिंक किए गए पृष्ठ बदल जाते हैं।
टोलोप्रॉड

आपकी टिप्पणी के लिए धन्यवाद, मैंने प्रश्न संपादित किया है। @tomloprod
N Jay

4
यह मेरा पसंदीदा उपाय है। हालाँकि, यह नोट करना महत्वपूर्ण है कि, जब आप स्रोत के रूप में नए वेक्टर ड्रा करने योग्य प्रकारों का उपयोग कर रहे हैं, तो यह समाधान काम नहीं करता है।
माइकल डी सोटो

1
@haagmm इस समाधान के लिए API> = 21 की आवश्यकता है। साथ ही यह वैक्टर के लिए भी काम करता है।
न्यूरोट्रांसमीटर

1
और यह वैक्टर के साथ काम नहीं करना चाहिए, रूट टैग है bitmap। वैक्टर को रंग देने के अन्य तरीके हैं। शायद किसी को यहाँ भी रंग ... वेक्टर जोड़ सकता है
milosmns

11

इस धागे में अधिकांश समाधान या तो एक नया एपीआई का उपयोग करते हैं, या प्रतिबिंब का उपयोग करते हैं, या फुलाए जाने के लिए गहन दृश्य लुकअप का उपयोग करते हैं MenuItem

हालाँकि, ऐसा करने के लिए एक और अधिक सुंदर दृष्टिकोण है। आपको एक कस्टम टूलबार की आवश्यकता है, क्योंकि आपका "कस्टम टिंट लागू करें" का उपयोग सार्वजनिक स्टाइल / थीमिंग एपीआई के साथ अच्छी तरह से नहीं करता है।

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

}

बस सुनिश्चित करें कि आप अपने गतिविधि / फ्रैगमेंट कोड में कॉल करते हैं:

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

कोई प्रतिबिंब नहीं, कोई दृश्य खोज नहीं और इतना कोड नहीं, हुह?

और अब आप हास्यास्पद को अनदेखा कर सकते हैं onCreateOptionsMenu/onOptionsItemSelected


तकनीकी रूप से, आप एक दृश्य खोज कर रहे हैं। आप विचारों को प्रसारित कर रहे हैं और सुनिश्चित कर रहे हैं कि वे शून्य नहीं हैं। ;)
मार्टिन मार्कोसिनी

आप निश्चित रूप से एक तरह से सही हैं :-) फिर भी, Menu#getItem()टूलबार में जटिलता O (1) है, क्योंकि आइटम ArrayList में संग्रहीत हैं। जो View#findViewByIdट्रैवर्सल से अलग है (जिसे मैंने अपने उत्तर में देखने के रूप में संदर्भित किया है ), जिसकी जटिलता दूर होने से निरंतर है :-)
ड्रू

सहमत, वास्तव में, मैंने एक बहुत ही समान काम किया। मैं अभी भी हैरान हूं कि इतने सालों के बाद एंड्रॉइड ने यह सब सुव्यवस्थित नहीं किया है ...
मार्टिन मार्कोसिनी

मैं इस दृष्टिकोण के साथ अतिप्रवाह आइकन और हैमबर्गर आइकन के रंगों को कैसे बदल सकता हूं?
सैंड्रा

8

यहाँ समाधान है जो मैं उपयोग करता हूं; आप इसे onPrepareOptionsMenu () या समकक्ष स्थान के बाद कॉल कर सकते हैं। म्यूट करने का कारण () यदि आप आइकन का उपयोग एक से अधिक स्थानों पर करते हैं; उत्परिवर्तन के बिना, वे सभी एक ही रंग में लेंगे।

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 के रूप में काम करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.