Android AppCompat 23.1.0 Tinte Compuesto Dibujable
Yo estaba usando el método a continuación para matizar adecuadamente compuestos con android.support.design 23.0.1. Ahora que lanzaron 23.1.0 ya no funciona en api LVL16, todos mis drawables son negros.
¿Alguien tiene una sugerencia?
- Android BottomSheetDialogFragment no se expande por completo
- Cómo ocultar la barra de herramientas cuando desplazamiento de contenido en android
- La vista no puede anclarse en el parámetro CoordinatorLayout principal
- Cómo agregar Snackbars en un BroadcastReceiver?
- Android KitKat: android.view.InflateException: Error al inflar la clase android.support.design.widget.NavigationView
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); }
Gracias.
- Error al inflar la clase CollapsingToolbarLayout
- InflateException con FloatingActionButton de la biblioteca de diseño oficial
- AppBarLayout.setExpanded (boolean, true) animación extraña en la biblioteca de soporte 23.1.1
- Problema con la biblioteca de asistencia de Android 23.2.1 AppBarLayout setExpanded
- CollapsingToolbarLayout con título multilínea
- Una vez más obtener java.lang.NoClassDefFoundError: android.support.v7.internal.view.menu.i después de actualizar a Herramientas de soporte 23
- Cambiar los iconos TabLayout a la izquierda, arriba, derecha o abajo en com.android.support:design:23.1.0
- Cómo configurar la elevación de un AppBarLayout mediante programación en la Biblioteca de soporte de Android v24.0.0?
Me enfrenté al mismo problema la semana pasada, y resulta en el AppCompatTextView v23.1.0, compuesto drawables se tiñen automáticamente.
Aquí está la solución que encontré, con más explicaciones sobre por qué hice esto a continuación. No es muy limpio, pero por lo menos le permite teñir su compuesto drawables!
SOLUCIÓN
Ponga este código en una clase de ayuda o en su personalizado TextView / Button:
/** * 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(); } }
Entonces puede llamar a removeDefaultTinting(this);
En cada constructor de su clase extendiendo AppCompatTextView o AppCompatButton. Por ejemplo :
public MyCustomTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); removeDefaultTinting(this); }
Con esto, el código que trabaja con v23.0.1 debería funcionar en v23.1.0.
No estoy satisfecho por el uso de la reflexión para cambiar los atributos en el AppCompat lib, pero esta es la única manera que encontré para usar el tintado en compuestos con drawables v23.1.0. Ojalá alguien encuentre una solución mejor, o tinte matizado compuesto será agregado a los métodos públicos de AppCompat.
ACTUALIZAR
Encontré otra solución más sencilla: este error sólo ocurre si se establecen elementos compuestos con xml. No los ponga en xml, entonces los fija en su código y trabajará. El código defectuoso que está en el constructor, la configuración de drawables después de que se ha llamado no se ve afectada.
EXPLICACIONES
En el constructor AppCompatTextView, se inicializa un ayudante de texto:
mTextHelper.loadFromAttributes(attrs, defStyleAttr); mTextHelper.applyCompoundDrawablesTints();
En la función TextHelper loadFromAttributes
, se crea una lista de tinte para cada compuesto dibujable. Como se puede ver, mDrawableXXXTint.mHasTintList
siempre se establece en true. mDrawableXXXTint.mTintList
es el color de tinte que se aplicará y sólo se obtiene de los valores de AppComm. Para su drawables personalizado, siempre será nulo. Así que terminan con un tinte que tiene una "lista de tinte nula".
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)); } ...
El problema es que este tinte se aplica en el constructor, y cada vez que un dibujable se establece o cambia:
@Override protected void drawableStateChanged() { super.drawableStateChanged(); if (mBackgroundTintHelper != null) { mBackgroundTintHelper.applySupportBackgroundTint(); } if (mTextHelper != null) { mTextHelper.applyCompoundDrawablesTints(); } }
Por lo tanto, si aplica un matiz a un compuesto dibujable y luego llama a un método super como view.setCompoundDrawablesRelativeWithIntrinsicBounds
, el ayudante de texto aplicará su tono nulo a su dibujable, eliminando todo lo que ha hecho …
Finalmente, aquí está la función que aplica el tinte:
final void applyCompoundDrawableTint(Drawable drawable, TintInfo info) { if (drawable != null && info != null) { TintManager.tintDrawable(drawable, info, mView.getDrawableState()); } }
El parámetro TintInfo
es el atributo mDrawableXXXTint
de la clase texthelper. Como puede ver, si es nulo, no se aplica tinte. Establecer todos los atributos de matiz dibujables en null impide que AppCompat aplique su tinte y le permite hacer lo que quiera con los drawables.
No encontré una manera limpia de bloquear este comportamiento o conseguir que aplicara el tinte que quiero. Todos los atributos son privados, sin getters.
- Android: ¿por qué consigo estos AsyncTask Error?
- No se puede generar APK después de agregar Google Analytics, pero funciona bien en modo de depuración