绘制包含InsetDrawable的图层时出现意外的LayerDrawable行为

时间:2012-01-27 05:16:08

标签: android drawable

我正在尝试在xml中构建一个LayerDrawable,其中上层偶尔会完全遮盖下层。为了使较低层较小,我使用InsetDrawable来包装另一个drawable,使其小于视图的完整大小。然而,我意外地发现,放置在包含插图的图层顶部的任何图层也都应用了插图。我找不到支持这种行为的文档,我很困惑为什么会出现这种情况。

在下面的示例中,我创建了一个包含3层的LayerDrawable。底层和顶层包含椭圆形的drawables,用于占据整个视图。中间层是InsetDrawable内部的矩形绘制。代码如下:

<?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>

在我的视图中调用setBackgroundDrawable(getResources().getDrawable(drawableId));会产生一个绿色椭圆,按预期填充整个视图,红色矩形按预期插入4dp,但顶层的蓝色椭圆也插入4dp并完全在红色矩形的边界。

我希望蓝色椭圆完全遮盖绿色椭圆和大部分红色矩形,但它会嵌入红色矩形内。有没有办法让蓝色圆圈填满视图但仍保持在顶部?

2 个答案:

答案 0 :(得分:10)

我也看不到它的记录位置,但LayerDrawable中的填充是累积的。也就是说,一层填充会影响所有较高层的边界。这来自the source for 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)遵循相同的逻辑。)由于InsetDrawable使用其插入作为填充(如documented),这解释了您所看到的行为。

我认为这是一个糟糕的设计决定,但是我很害怕。我不认为它可以被覆盖。

答案 1 :(得分:2)

Ted的回答是最好的答案,但我会分享这个帮助我的解决方法。我特意使用TextView填充问题,所以我做了一个自定义TextView而忽略了背景drawable的填充。

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

}