Comportamiento inesperado de LayerDrawable cuando se dibujan capas que contienen InsetDrawable

Estoy tratando de construir un LayerDrawable en xml donde capas superiores de vez en cuando completamente oscurecer capas inferiores. Para hacer las capas inferiores más pequeñas, estoy usando un InsetDrawable para envolver otro dibujable para hacerlo más pequeño que el tamaño completo de la vista. Sin embargo, encuentro inesperadamente que cualquier capa colocada encima de la capa que contiene la inserción también tiene la inserción aplicada a ella. No puedo encontrar documentación que respalde este comportamiento, y estoy confundido por qué este sería el caso.

En el ejemplo siguiente, hago un LayerDrawable con 3 capas. Las capas inferiores y superiores contienen elementos de forma ovalados que se destinan a ocupar toda la vista. La capa intermedia es un rectángulo dibujable dentro de un InsetDrawable. El código está abajo:

<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape android:shape="oval" > <solid android:color="#00ff00" /> </shape> </item> <item> <inset android:insetBottom="4dp" android:insetLeft="4dp" android:insetRight="4dp" android:insetTop="4dp" > <shape android:shape="rectangle" > <solid android:color="#ff0000" /> </shape> </inset> </item> <item> <shape android:shape="oval" > <solid android:color="#0000ff" /> </shape> </item> </layer-list> 

Llamando setBackgroundDrawable(getResources().getDrawable(drawableId)); En mi opinión produce un óvalo verde que llena toda la vista como se esperaba, con un rectángulo rojo insertado 4dp como se esperaba, pero el óvalo azul en la capa superior también es insertar 4dp y dibujado completamente dentro de los límites del rectángulo rojo.

Esperaría que el óvalo azul oscurezca completamente el óvalo verde y la mayor parte del rectángulo rojo, pero en su lugar está insertado dentro del rectángulo rojo. ¿Hay alguna manera de hacer que el círculo azul llene la vista y la mantenga en la parte superior?

También no veo donde está documentado, pero el relleno en un LayerDrawable es acumulativo. Es decir, el relleno en una capa afecta los límites de todas las capas superiores. Esto es de la fuente para LayerDrawable :

 @Override protected void onBoundsChange(Rect bounds) { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; int padL=0, padT=0, padR=0, padB=0; for (int i=0; i<N; i++) { final ChildDrawable r = array[i]; r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, bounds.top + r.mInsetT + padT, bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB); padL += mPaddingL[i]; padR += mPaddingR[i]; padT += mPaddingT[i]; padB += mPaddingB[i]; } } 

( LayerDrawable.getPadding(Rect) sigue la misma lógica.) Dado que un InsetDrawable utiliza sus inserciones como relleno (como se documenta ), esto explica el comportamiento que está viendo.

Creo que esta es una mala decisión de diseño, pero estás un poco atascado con eso, me temo. No creo que pueda ser anulada.

La respuesta de Ted es la mejor, pero compartiré esta solución que me ayudó. Yo estaba específicamente teniendo problemas de relleno con un TextView, así que hice un TextView personalizado en su lugar que ignora el relleno de dibujo de fondo.

 public class HackTextView extends TextView { public HackTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public HackTextView(Context context, AttributeSet attrs) { super(context, attrs); } public HackTextView(Context context) { super(context); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public void setBackground(Drawable background) { super.setBackground(hackDrawable(background)); } @Override public void setBackgroundDrawable(Drawable background) { super.setBackgroundDrawable(hackDrawable(background)); } private Drawable hackDrawable(Drawable background){ return new LayerDrawable(new Drawable[]{background}){ @Override public boolean getPadding(Rect padding) { padding.set(0, 0, 0, 0); return false; } }; } } 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.