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.
sprawdź [tę odpowiedź] (http://stackoverflow.com/a/35867517/2826147) w celu aktualizacji. –
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