6

मैं एंड्रॉइड.support.design 23.0.1 के साथ कंपाउंड ड्रॉबल्स को सही तरीके से टेंट करने के लिए नीचे दी गई विधि का उपयोग कर रहा था। अब जब उन्होंने 23.1.0 जारी किया है, यह अब एपीआई एलवीएल 16 पर काम नहीं करता है, मेरे सभी ड्रॉबल्स काले हैं।एंड्रॉइड ऐपकंपेट 23.1.0 टिंट कंपाउंड ड्रायबल

किसी के पास कोई सुझाव है?

private void setCompoundColor(TextView view) { 
    Drawable drawable = view.getCompoundDrawables()[0]; 
    Drawable wrap = DrawableCompat.wrap(drawable); 
    DrawableCompat.setTint(wrap, ContextCompat.getColor(this, R.color.primaryLighter2)); 
    DrawableCompat.setTintMode(wrap, PorterDuff.Mode.SRC_IN); 
    wrap = wrap.mutate(); 
    view.setCompoundDrawablesRelativeWithIntrinsicBounds(wrap, null, null, null); 
    } 

धन्यवाद।

+1

अद्यतन के लिए [यह उत्तर] (http://stackoverflow.com/a/35867517/2826147) देखें। –

+0

फिलिप डेविड का कोड काम करता है, लेकिन मेरे अनुभव से आपको 'wrapableCompat.setTint()' से पहले 'wrap = wrap.mutate();' लिखना चाहिए। अन्यथा यह ठीक से काम नहीं करेगा क्योंकि मूल खींचने योग्य संशोधित किया जाएगा। – marius

उत्तर

8

मुझे पिछले सप्ताह एक ही समस्या का सामना करना पड़ा, और यह AppCompatTextView v23.1.0 में निकला, कंपाउंड ड्रॉबल्स स्वचालित रूप से टिंटेड होते हैं।

यहां मैंने जो समाधान पाया है, उससे अधिक स्पष्टीकरण के साथ मैंने नीचे क्यों किया। यह बहुत साफ नहीं है लेकिन कम से कम यह आपको अपने यौगिक drawables टिंट करने में सक्षम बनाता है!

समाधान

रखें इस कोड को एक सहायक कक्षा में या अपने कस्टम TextView/बटन में:

/** 
* The app compat text view automatically sets the compound drawable tints for a static array of drawables ids. 
* If the drawable id is not in the list, the lib apply a null tint, removing the custom tint set before. 
* There is no way to change this (private attributes/classes, only set in the constructor...) 
* 
* @param object the object on which to disable default tinting. 
*/ 
public static void removeDefaultTinting(Object object) { 
    try { 
     // Get the text helper field. 
     Field mTextHelperField = object.getClass().getSuperclass().getDeclaredField("mTextHelper"); 
     mTextHelperField.setAccessible(true); 
     // Get the text helper object instance. 
     final Object mTextHelper = mTextHelperField.get(object); 
     if (mTextHelper != null) { 
      // Apply tint to all private attributes. See AppCompat source code for usage of theses attributes. 
      setObjectFieldToNull(mTextHelper, "mDrawableStartTint"); 
      setObjectFieldToNull(mTextHelper, "mDrawableEndTint"); 
      setObjectFieldToNull(mTextHelper, "mDrawableLeftTint"); 
      setObjectFieldToNull(mTextHelper, "mDrawableTopTint"); 
      setObjectFieldToNull(mTextHelper, "mDrawableRightTint"); 
      setObjectFieldToNull(mTextHelper, "mDrawableBottomTint"); 
     } 
    } catch (NoSuchFieldException e) { 
     // If it doesn't work, we can do nothing else. The icons will be white, we will see it. 
     e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
     // If it doesn't work, we can do nothing else. The icons will be white, we will see it. 
     e.printStackTrace(); 
    } 
} 

/** 
* Set the field of an object to null. 
* 
* @param object the TextHelper object (class is not accessible...). 
* @param fieldName the name of the tint field. 
*/ 
private static void setObjectFieldToNull(Object object, String fieldName) { 
    try { 
     Field tintField; 
     // Try to get field from class or super class (depends on the implementation). 
     try { 
      tintField = object.getClass().getDeclaredField(fieldName); 
     } catch (NoSuchFieldException e) { 
      tintField = object.getClass().getSuperclass().getDeclaredField(fieldName); 
     } 
     tintField.setAccessible(true); 
     tintField.set(object, null); 

    } catch (NoSuchFieldException e) { 
     // If it doesn't work, we can do nothing else. The icons will be white, we will see it. 
     e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
     // If it doesn't work, we can do nothing else. The icons will be white, we will see it. 
     e.printStackTrace(); 
    } 
} 

तो फिर आप अपने वर्ग AppCompatTextView या AppCompatButton विस्तार से प्रत्येक निर्माता पर removeDefaultTinting(this); कॉल कर सकते हैं। उदाहरण के लिए:

public MyCustomTextView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    removeDefaultTinting(this); 
} 

इसके साथ, v23.0.1 के साथ काम करने वाला कोड v23.1.0 पर काम करना चाहिए।

मैं AppCompat lib में विशेषताओं को बदलने के प्रतिबिंब के उपयोग से संतुष्ट नहीं हूं, लेकिन यह एकमात्र तरीका है जिसे मैंने v23.1.0 के साथ यौगिक drawables पर टिनटिंग का उपयोग करने के लिए पाया है। उम्मीद है कि किसी को बेहतर समाधान मिलेगा, या यौगिक ड्रॉबल टिनटिंग AppCompat सार्वजनिक विधियों में जोड़ा जाएगा।

अद्यतन

मैं एक सरल समाधान मिला: इस बग होता है केवल यदि आप यौगिक ड्रॉएबल एक्सएमएल का उपयोग कर निर्धारित किया है। उन्हें एक्सएमएल में सेट न करें, फिर उन्हें अपने कोड में सेट करें और यह काम करेगा। कन्स्ट्रक्टर में दोषपूर्ण कोड है, इसे कॉल करने के बाद ड्रॉबल्स सेट करना प्रभावित नहीं है।

explications

AppCompatTextView निर्माता में, एक पाठ सहायक आरंभ नहीं हो जाता:

mTextHelper.loadFromAttributes(attrs, defStyleAttr); 
mTextHelper.applyCompoundDrawablesTints(); 

TextHelper loadFromAttributes समारोह में, एक टिंट सूची प्रत्येक यौगिक drawable के लिए बनाया जाता है। जैसा कि आप देख सकते हैं, mDrawableXXXTint.mHasTintList हमेशा सत्य पर सेट है। mDrawableXXXTint.mTintList टिंट रंग है जो लागू किया जाएगा, और केवल AppCompat के हार्डकोडेड मानों से प्राप्त होता है। आपके कस्टम ड्रॉबल्स के लिए, यह हमेशा शून्य होगा। तो आप एक टिंट के साथ एक शून्य "टिंट सूची" के साथ समाप्त होता है।

@Override 
protected void drawableStateChanged() { 
    super.drawableStateChanged(); 
    if (mBackgroundTintHelper != null) { 
     mBackgroundTintHelper.applySupportBackgroundTint(); 
    } 
    if (mTextHelper != null) { 
     mTextHelper.applyCompoundDrawablesTints(); 
    } 
} 

तो अगर आप एक यौगिक drawable करने के लिए एक रंग लागू होते हैं, और फिर कहते हैं:

TypedArray a = context.obtainStyledAttributes(attrs, VIEW_ATTRS, defStyleAttr, 0); 
    final int ap = a.getResourceId(0, -1); 

    // Now read the compound drawable and grab any tints 
    if (a.hasValue(1)) { 
     mDrawableLeftTint = new TintInfo(); 
     mDrawableLeftTint.mHasTintList = true; 
     mDrawableLeftTint.mTintList = tintManager.getTintList(a.getResourceId(1, 0)); 
    } 
    if (a.hasValue(2)) { 
     mDrawableTopTint = new TintInfo(); 
     mDrawableTopTint.mHasTintList = true; 
     mDrawableTopTint.mTintList = tintManager.getTintList(a.getResourceId(2, 0)); 
    } 

... 
समस्या

है कि इस रंग निर्माता में लागू किया जाता है, और हर बार एक drawable सेट कर दिया जाता है या उसमें बदलाव है एक सुपर विधि जैसे कि view.setCompoundDrawablesRelativeWithIntrinsicBounds, टेक्स्ट हेल्पर आपके ड्रॉबल को अपना नल टिंट लागू करेगा, जो कुछ भी आपने किया है उसे हटा दें ...

final void applyCompoundDrawableTint(Drawable drawable, TintInfo info) { 
    if (drawable != null && info != null) { 
     TintManager.tintDrawable(drawable, info, mView.getDrawableState()); 
    } 
} 

TintInfo मानकों में texthelper वर्ग के mDrawableXXXTint विशेषता है:

अंत में, यहाँ समारोह टिंट लागू करने के लिए है। जैसा कि आप देख सकते हैं, अगर यह शून्य है, तो कोई टिंट लागू नहीं होता है। सभी खींचने योग्य टिंट विशेषताओं को शून्य पर सेट करने से AppCompat को इसके टिंट को लागू करने से रोकता है, और आपको ड्रैबल्स के साथ इच्छित वॉथर करने में सक्षम बनाता है।

मुझे इस व्यवहार को अवरुद्ध करने या इसे प्राप्त करने के लिए इसे प्राप्त करने का एक साफ तरीका नहीं मिला। सभी गुण निजी हैं, बिना किसी गेटर्स के।

+0

वाह। मैंने जवाब नहीं दिया कि मुझे किस तरह का जवाब मिलेगा! आपके समाधान का प्रयास करेंगे, लेकिन इस तरह का काम एंड्रॉइड के लिए शर्म की बात है ... क्या आपको लगता है कि Google के लिए एक बग खोलना बुद्धिमान होगा? बहुत बहुत धन्यवाद :) –

+3

आपका स्वागत है! मैंने डीबगर का उपयोग करके आधे दिन बिताए ताकि यह समझ सके कि मेरे ड्रॉबल्स सफेद क्यों थे, इसलिए जब मैंने आपका प्रश्न देखा तो मुझे एक खाता बनाने के लिए बाध्य महसूस हुआ और मुझे जो मिला वह पोस्ट करें :) शायद यह एक अच्छा विचार है कि एक बग खोलने के लिए, मैंने अभी किया समय नहीं लेना यह एक अस्थायी समाधान है जो अगली बार जब वे AppCompat संशोधित करता है तो काम करना बंद कर देगा। वे कंपाउंड ड्रॉबल्स को टेंट करने के लिए उपयोग किए जाने वाले कोड बहुत लंबे या जटिल नहीं होते हैं, यह बाहरी कक्षा से पूरी तरह से पहुंच योग्य नहीं है। प्रत्येक यौगिक drawables के टिंट के लिए एक सरल सेटटर, और यह तय है ... –

+1

इस मुद्दे के लिए किया गया। कल से, मुझे पता चला कि यह lib कुछ डिवाइस पर ट्रांजिशन ड्रावर को तोड़ देता है :) https://code.google.com/p/android/issues/detail?id=191111 –

संबंधित मुद्दे