FileDocCategorySizeDatePackage
LayerDrawable.javaAPI DocAndroid 1.5 API21316Wed May 06 22:42:00 BST 2009android.graphics.drawable

LayerDrawable

public class LayerDrawable extends Drawable implements Drawable.Callback
A Drawable that manages an array of other Drawables. These are drawn in array order, so the element with the largest index will be drawn on top.

It can be defined in an XML file with the <layer-list> element. Each Drawable in the layer is defined in a nested <item>.

attr
ref android.R.styleable#LayerDrawableItem_left
attr
ref android.R.styleable#LayerDrawableItem_top
attr
ref android.R.styleable#LayerDrawableItem_right
attr
ref android.R.styleable#LayerDrawableItem_bottom
attr
ref android.R.styleable#LayerDrawableItem_drawable
attr
ref android.R.styleable#LayerDrawableItem_id

Fields Summary
LayerState
mLayerState
private int[]
mPaddingL
private int[]
mPaddingT
private int[]
mPaddingR
private int[]
mPaddingB
private final Rect
mTmpRect
private boolean
mMutated
Constructors Summary
public LayerDrawable(Drawable[] layers)
Create a new layer drawable with the list of specified layers.

param
layers A list of drawables to use as layers in this new drawable.


                                  
       
        this(layers, null);
    
LayerDrawable(Drawable[] layers, LayerState state)
Create a new layer drawable with the specified list of layers and the specified constant state.

param
layers The list of layers to add to this drawable.
param
state The constant drawable state.

        this(state);
        int length = layers.length;
        ChildDrawable[] r = new ChildDrawable[length];

        for (int i = 0; i < length; i++) {
            r[i] = new ChildDrawable();
            r[i].mDrawable = layers[i];
            layers[i].setCallback(this);
            mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations();
        }
        mLayerState.mNum = length;
        mLayerState.mChildren = r;

        ensurePadding();
    
LayerDrawable()

        this((LayerState) null);
    
LayerDrawable(LayerState state)

        LayerState as = createConstantState(state);
        mLayerState = as;
        if (as.mNum > 0) {
            ensurePadding();
        }
    
Methods Summary
private voidaddLayer(Drawable layer, int id, int left, int top, int right, int bottom)
Add a new layer to this drawable. The new layer is identified by an id.

param
layer The drawable to add as a layer.
param
id The id of the new layer.
param
left The left padding of the new layer.
param
top The top padding of the new layer.
param
right The right padding of the new layer.
param
bottom The bottom padding of the new layer.

        final LayerState st = mLayerState;
        int N = st.mChildren != null ? st.mChildren.length : 0;
        int i = st.mNum;
        if (i >= N) {
            ChildDrawable[] nu = new ChildDrawable[N + 10];
            if (i > 0) {
                System.arraycopy(st.mChildren, 0, nu, 0, i);
            }
            st.mChildren = nu;
        }

        mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations();
        
        ChildDrawable childDrawable = new ChildDrawable();
        st.mChildren[i] = childDrawable;
        childDrawable.mId = id;
        childDrawable.mDrawable = layer;
        childDrawable.mInsetL = left;
        childDrawable.mInsetT = top;
        childDrawable.mInsetR = right;
        childDrawable.mInsetB = bottom;
        st.mNum++;

        layer.setCallback(this);
    
android.graphics.drawable.LayerDrawable$LayerStatecreateConstantState(android.graphics.drawable.LayerDrawable$LayerState state)

        return new LayerState(state, this);
    
public voiddraw(Canvas canvas)

        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        for (int i=0; i<N; i++) {
            array[i].mDrawable.draw(canvas);
        }
    
private voidensurePadding()

        final int N = mLayerState.mNum;
        if (mPaddingL != null && mPaddingL.length >= N) {
            return;
        }
        mPaddingL = new int[N];
        mPaddingT = new int[N];
        mPaddingR = new int[N];
        mPaddingB = new int[N];
    
public DrawablefindDrawableByLayerId(int id)
Look for a layer with the given id, and returns its {@link Drawable}.

param
id The layer ID to search for.
return
The {@link Drawable} of the layer that has the given id in the hierarchy or null.

        final ChildDrawable[] layers = mLayerState.mChildren;
        
        for (int i = mLayerState.mNum - 1; i >= 0; i--) {
            if (layers[i].mId == id) {
                return layers[i].mDrawable;
            }
        }
        
        return null;
    
public intgetChangingConfigurations()

        return super.getChangingConfigurations()
                | mLayerState.mChangingConfigurations
                | mLayerState.mChildrenChangingConfigurations;
    
public ConstantStategetConstantState()

        if (mLayerState.canConstantState()) {
            mLayerState.mChangingConfigurations = super.getChangingConfigurations();
            return mLayerState;
        }
        return null;
    
public DrawablegetDrawable(int index)
Returns the drawable at the specified layer index.

param
index The layer index of the drawable to retrieve.
return
The {@link android.graphics.drawable.Drawable} at the specified layer index.

        return mLayerState.mChildren[index].mDrawable;
    
public intgetId(int index)
Returns the id of the specified layer.

param
index The index of the layer.
return
The id of the layer or {@link android.view.View#NO_ID} if the layer has no id.

        return mLayerState.mChildren[index].mId;
    
public intgetIntrinsicHeight()

        int height = -1;
        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        int padT=0, padB=0;
        for (int i=0; i<N; i++) {
            final ChildDrawable r = array[i];
            int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + + padT + padB;
            if (h > height) {
                height = h;
            }
            padT += mPaddingT[i];
            padB += mPaddingB[i];
        }
        return height;
    
public intgetIntrinsicWidth()

        int width = -1;
        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        int padL=0, padR=0;
        for (int i=0; i<N; i++) {
            final ChildDrawable r = array[i];
            int w = r.mDrawable.getIntrinsicWidth()
                  + r.mInsetL + r.mInsetR + padL + padR;
            if (w > width) {
                width = w;
            }
            padL += mPaddingL[i];
            padR += mPaddingR[i];
        }
        return width;
    
public intgetNumberOfLayers()
Returns the number of layers contained within this.

return
The number of layers.

        return mLayerState.mNum;
    
public intgetOpacity()

        return mLayerState.getOpacity();
    
public booleangetPadding(Rect padding)

        // Arbitrarily get the padding from the first image.
        // Technically we should maybe do something more intelligent,
        // like take the max padding of all the images.
        padding.left = 0;
        padding.top = 0;
        padding.right = 0;
        padding.bottom = 0;
        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        for (int i=0; i<N; i++) {
            reapplyPadding(i, array[i]);
            padding.left += mPaddingL[i];
            padding.top += mPaddingT[i];
            padding.right += mPaddingR[i];
            padding.bottom += mPaddingB[i];
        }
        return true;
    
public voidinflate(android.content.res.Resources r, org.xmlpull.v1.XmlPullParser parser, android.util.AttributeSet attrs)

        super.inflate(r, parser, attrs);

        int type;

        final int innerDepth = parser.getDepth() + 1;
        int depth;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
            if (type != XmlPullParser.START_TAG) {
                continue;
            }

            if (depth > innerDepth || !parser.getName().equals("item")) {
                continue;
            }

            TypedArray a = r.obtainAttributes(attrs,
                    com.android.internal.R.styleable.LayerDrawableItem);

            int left = a.getDimensionPixelOffset(
                    com.android.internal.R.styleable.LayerDrawableItem_left, 0);
            int top = a.getDimensionPixelOffset(
                    com.android.internal.R.styleable.LayerDrawableItem_top, 0);
            int right = a.getDimensionPixelOffset(
                    com.android.internal.R.styleable.LayerDrawableItem_right, 0);
            int bottom = a.getDimensionPixelOffset(
                    com.android.internal.R.styleable.LayerDrawableItem_bottom, 0);
            int drawableRes = a.getResourceId(
                    com.android.internal.R.styleable.LayerDrawableItem_drawable, 0);
            int id = a.getResourceId(com.android.internal.R.styleable.LayerDrawableItem_id,
                    View.NO_ID);

            a.recycle();

            Drawable dr;
            if (drawableRes != 0) {
                dr = r.getDrawable(drawableRes);
            } else {
                while ((type = parser.next()) == XmlPullParser.TEXT) {
                }
                if (type != XmlPullParser.START_TAG) {
                    throw new XmlPullParserException(parser.getPositionDescription()
                            + ": <item> tag requires a 'drawable' attribute or "
                            + "child tag defining a drawable");
                }
                dr = Drawable.createFromXmlInner(r, parser, attrs);
            }

            addLayer(dr, id, left, top, right, bottom);
        }

        ensurePadding();
        onStateChange(getState());
    
public voidinvalidateDrawable(Drawable who)

        if (mCallback != null) {
            mCallback.invalidateDrawable(this);
        }
    
public booleanisStateful()

        return mLayerState.isStateful();
    
public Drawablemutate()

        if (!mMutated && super.mutate() == this) {
            final ChildDrawable[] array = mLayerState.mChildren;
            final int N = mLayerState.mNum;
            for (int i = 0; i < N; i++) {
                array[i].mDrawable.mutate();
            }
            mMutated = true;
        }
        return this;
    
protected voidonBoundsChange(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];
        }
    
protected booleanonLevelChange(int level)

        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        boolean paddingChanged = false;
        boolean changed = false;
        for (int i=0; i<N; i++) {
            final ChildDrawable r = array[i];
            if (r.mDrawable.setLevel(level)) {
                changed = true;
            }
            if (reapplyPadding(i, r)) {
                paddingChanged = true;
            }
        }
        if (paddingChanged) {
            onBoundsChange(getBounds());
        }
        return changed;
    
protected booleanonStateChange(int[] state)

        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        boolean paddingChanged = false;
        boolean changed = false;
        for (int i=0; i<N; i++) {
            final ChildDrawable r = array[i];
            if (r.mDrawable.setState(state)) {
                changed = true;
            }
            if (reapplyPadding(i, r)) {
                paddingChanged = true;
            }
        }
        if (paddingChanged) {
            onBoundsChange(getBounds());
        }
        return changed;
    
private booleanreapplyPadding(int i, android.graphics.drawable.LayerDrawable$ChildDrawable r)

        final Rect rect = mTmpRect;
        r.mDrawable.getPadding(rect);
        if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] ||
                rect.right != mPaddingR[i] || rect.bottom != mPaddingB[i]) {
            mPaddingL[i] = rect.left;
            mPaddingT[i] = rect.top;
            mPaddingR[i] = rect.right;
            mPaddingB[i] = rect.bottom;
            return true;
        }
        return false;
    
public voidscheduleDrawable(Drawable who, java.lang.Runnable what, long when)

        if (mCallback != null) {
            mCallback.scheduleDrawable(this, what, when);
        }
    
public voidsetAlpha(int alpha)

        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        for (int i=0; i<N; i++) {
            array[i].mDrawable.setAlpha(alpha);
        }
    
public voidsetColorFilter(ColorFilter cf)

        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        for (int i=0; i<N; i++) {
            array[i].mDrawable.setColorFilter(cf);
        }
    
public voidsetDither(boolean dither)

        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        for (int i=0; i<N; i++) {
            array[i].mDrawable.setDither(dither);
        }
    
public booleansetDrawableByLayerId(int id, Drawable drawable)
Sets (or replaces) the {@link Drawable} for the layer with the given id.

param
id The layer ID to search for.
param
drawable The replacement {@link Drawable}.
return
Whether the {@link Drawable} was replaced (could return false if the id was not found).

        final ChildDrawable[] layers = mLayerState.mChildren;
        
        for (int i = mLayerState.mNum - 1; i >= 0; i--) {
            if (layers[i].mId == id) {
                layers[i].mDrawable = drawable;
                return true;
            }
        }
        
        return false;
    
public voidsetId(int index, int id)
Sets the ID of a layer.

param
index The index of the layer which will received the ID.
param
id The ID to assign to the layer.

        mLayerState.mChildren[index].mId = id;
    
public voidsetLayerInset(int index, int l, int t, int r, int b)
Specify modifiers to the bounds for the drawable[index]. left += l top += t; right -= r; bottom -= b;

        ChildDrawable childDrawable = mLayerState.mChildren[index];
        childDrawable.mInsetL = l;
        childDrawable.mInsetT = t;
        childDrawable.mInsetR = r;
        childDrawable.mInsetB = b;
    
public booleansetVisible(boolean visible, boolean restart)

        boolean changed = super.setVisible(visible, restart);
        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        for (int i=0; i<N; i++) {
            array[i].mDrawable.setVisible(visible, restart);
        }
        return changed;
    
public voidunscheduleDrawable(Drawable who, java.lang.Runnable what)

        if (mCallback != null) {
            mCallback.unscheduleDrawable(this, what);
        }