6

Użyłem poniższej metody, aby właściwie zabarwić złożone rysunki za pomocą android.support.design 23.0.1. Teraz, gdy wydali 23.1.0, nie działa już na api LVL16, wszystkie moje rysunki są czarne.Android AppCompat 23.1.0 Tint Compound Drawable

Ktoś ma sugestię?

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

Dzięki.

+1

sprawdź [tę odpowiedź] (http://stackoverflow.com/a/35867517/2826147) w celu aktualizacji. –

+0

Kod z Philippe David działa, ale z mojego doświadczenia powinieneś napisać 'wrap = wrap.mutate();' przed 'DrawableCompat.setTint()'. W przeciwnym razie nie będzie działać poprawnie, ponieważ oryginalny wyciąg zostanie zmodyfikowany. – marius

Odpowiedz

8

W zeszłym tygodniu stanąłem wobec tego samego problemu i okazuje się, że w zestawie AppCompatTextView v23.1.0, złożone rysunki są automatycznie przyciemniane.

Oto rozwiązanie, które znalazłem, z większą ilością wyjaśnień, dlaczego to zrobiłem poniżej. Nie jest bardzo czysty, ale przynajmniej umożliwia odbarwianie twoich złożonych rysunków!

ROZWIĄZANIE

umieścić ten kod w klasie pomocnika lub w niestandardowych TextView przycisk /:

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

Następnie można wywołać removeDefaultTinting(this); na każdego konstruktora klasy rozciągającej AppCompatTextView lub AppCompatButton. Na przykład:

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

Przy tym kod działający z v23.0.1 powinien działać na v23.1.0.

Nie jestem usatysfakcjonowany za pomocą refleksji, aby zmienić atrybuty w bibliotece AppCompat, ale jest to jedyny sposób, w jaki znalazłem zastosowanie barwienia dla złożonych rysunków w wersji 23.1.0. Mam nadzieję, że ktoś znajdzie lepsze rozwiązanie, lub mieszane podbarwianie zostanie dodane do publicznych metod AppCompat.

UPDATE

znalazłem inną prostsze rozwiązanie: ten błąd występuje tylko w przypadku ustawienia kanału alfa złożonych za pomocą XML. Nie ustawiaj ich w xml, a następnie ustawiaj w swoim kodzie i będzie działać. Błąd w konstruktorze, ustawianie rysunków po wywołaniu nie ma wpływu.

wyjaśnień

W konstruktora AppCompatTextView, pomocnikiem tekst jest inicjowany:

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

W funkcji TextHelper loadFromAttributes wykaz odcień jest tworzony dla każdej rozciągliwej związku. Jak widać, mDrawableXXXTint.mHasTintList jest zawsze ustawione na true. mDrawableXXXTint.mTintList to kolor tinty, który zostanie zastosowany, i jest uzyskiwany tylko z zakodowanych wartości AppCompat. W przypadku niestandardowych rysunków zawsze będzie mieć wartość NULL. W efekcie otrzymujesz odcień o zerowej liście kolorów.

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

... 

Problem polega na tym, że ten odcień jest stosowany w konstruktorze, a za każdym razem odkształcalne jest ustawione lub zmienione:

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

Więc jeśli zastosować odcień rozciągliwej związku, a następnie zadzwonić super-metoda taka jak view.setCompoundDrawablesRelativeWithIntrinsicBounds, pomocnik tekstowy zastosuje swój nullowy odcień do twojego losowania, usuwając wszystko, co zrobiłeś ...

Wreszcie jest tutaj funkcja stosując zabarwienie:

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

TintInfo parametrów jest atrybutem klasy texthelper mDrawableXXXTint. Jak widać, jeśli ma wartość zerową, nie stosuje się tinty. Ustawienie null wszystkich atrybutów tinty powoduje, że aplikacja AppCompat nie nakłada odcień i umożliwia wykonanie zadań według schematów.

Nie znalazłem sposobu, aby zablokować to zachowanie lub uzyskać pożądany odcień. Wszystkie atrybuty są prywatne, bez żadnych modułów pobierających.

+0

Wow. Nie taki rodzaj odpowiedzi, jaki myślałem, że dostanę! Wypróbuję twoje rozwiązanie, ale ten rodzaj pracy przynosi wstyd Androidowi ... Czy uważasz, że mądrze byłoby otworzyć błąd, który mógłby sprawdzić Google? Wielkie dzięki :) –

+3

Nie ma za co! Spędziłem pół dnia używając debuggera, aby zrozumieć, dlaczego moje rysunki są białe, więc kiedy zobaczyłem twoje pytanie, poczułem się zobowiązany do stworzenia konta i opublikowania tego, co znalazłem :) To chyba dobry pomysł, aby otworzyć błąd, właśnie zrobiłem Nie śpiesz się. Jest to rozwiązanie tymczasowe, które prawdopodobnie przestanie działać po następnym zmodyfikowaniu AppCompat. Kod, którego używają do odbarwiania złożonych rysunków, nie jest zbyt długi ani skomplikowany, a jest po prostu całkowicie niedostępny z zewnętrznej klasy. Prosty seter dla odcienia każdego złożonego rysunku i został naprawiony ... –

+1

Gotowe na wydanie. Od wczoraj dowiedziałem się, że ta lib również łamie TransitionDrawable na jakimś urządzeniu :) https://code.google.com/p/android/issues/detail?id=191111 –

Powiązane problemy