Я столкнулся с той же проблемой на прошлой неделе, и, как оказалось, в AppCompatTextView v23.1.0, составные чертежи автоматически тонируются.
Вот решение, которое я нашел, с более подробными объяснениями, почему я сделал это ниже. Его не очень чистый, но, по крайней мере, он позволяет вам подкрасить ваши составные чертежи!
РЕШЕНИЕ
Поместите этот код в вспомогательном классе или в пользовательских 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();
}
}
Тогда вы можете вызвать removeDefaultTinting(this);
на каждом конструкторе класса, простирающейся AppCompatTextView или AppCompatButton. Например:
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. Надеемся, что кто-то найдет лучшее решение, или составные тонированные цвета будут добавлены в общедоступные методы AppCompat.
UPDATE
Я нашел еще более простое решение: эта ошибка возникает, только если вы установили составные XML с помощью вводимого коэффициента. Не устанавливайте их в xml, а затем установите их в свой код, и он будет работать. Неисправный код, находящийся в конструкторе, устанавливающий чертежи после его вызова, не затрагивается.
экспликации
В AppCompatTextView конструктор, текстовый помощник инициализируется:
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
mTextHelper.applyCompoundDrawablesTints();
В функции TextHelper loadFromAttributes
, список Оттенок создается для каждого соединения Drawable. Как вы можете видеть, значение mDrawableXXXTint.mHasTintList
всегда равно true. mDrawableXXXTint.mTintList
- цвет оттенка, который будет применяться, и получить только от жестко заданных значений AppCompat. Для ваших пользовательских чертежей всегда будет null. Таким образом, вы получаете оттенок, имеющий нулевой «список оттенков».
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));
}
...
Проблема заключается в том, что этот оттенок применяется в конструкторе, и каждый раз, когда рисуем установлено или изменено:
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySupportBackgroundTint();
}
if (mTextHelper != null) {
mTextHelper.applyCompoundDrawablesTints();
}
}
Итак, если применить оттенок к сложному Drawable, а затем вызвать супер метод, такой как view.setCompoundDrawablesRelativeWithIntrinsicBounds
, текстовый помощник применит свой нулевой оттенок к вашему рисунку, удалив все, что вы сделали ...
Наконец, здесь есть функция нанесения оттенка:
final void applyCompoundDrawableTint(Drawable drawable, TintInfo info) {
if (drawable != null && info != null) {
TintManager.tintDrawable(drawable, info, mView.getDrawableState());
}
}
TintInfo
параметрами является mDrawableXXXTint
атрибутом класса TextHelper. Как вы можете видеть, если оно равно null, никакого оттенка не применяется. Установка всех атрибутов drawing tint на null запрещает AppCompat применять оттенок и позволяет вам делать то, что вы хотите, с помощью drawables.
Я не нашел чистого способа блокировать это поведение или заставить его применять оттенок, который я хочу. Все атрибуты являются частными, без геттеров.
проверить [этот ответ] (http://stackoverflow.com/a/35867517/2826147) для обновления. –
Код от Филиппа Дэвида работает, но из моего опыта вы должны написать 'wrap = wrap.mutate();' перед 'DrawableCompat.setTint()'. В противном случае он не будет работать должным образом, поскольку исходный файл будет изменен. – marius