FileDocCategorySizeDatePackage
DrawableContainer.javaAPI DocAndroid 5.1 API36714Thu Mar 12 22:22:30 GMT 2015android.graphics.drawable

DrawableContainer

public class DrawableContainer extends Drawable implements Drawable.Callback
A helper class that contains several {@link Drawable}s and selects which one to use. You can subclass it to create your own DrawableContainers or directly use one its child classes.

Fields Summary
private static final boolean
DEBUG
private static final String
TAG
private static final boolean
DEFAULT_DITHER
To be proper, we should have a getter for dither (and alpha, etc.) so that proxy classes like this can save/restore their delegates' values, but we don't have getters. Since we do have setters (e.g. setDither), which this proxy forwards on, we have to have some default/initial setting. The initial setting for dither is now true, since it almost always seems to improve the quality at negligible cost.
private DrawableContainerState
mDrawableContainerState
private android.graphics.Rect
mHotspotBounds
private Drawable
mCurrDrawable
private Drawable
mLastDrawable
private int
mAlpha
private boolean
mHasAlpha
Whether setAlpha() has been called at least once.
private int
mCurIndex
private int
mLastIndex
private boolean
mMutated
private Runnable
mAnimationRunnable
private long
mEnterAnimationEnd
private long
mExitAnimationEnd
Constructors Summary
Methods Summary
voidanimate(boolean schedule)

        mHasAlpha = true;

        final long now = SystemClock.uptimeMillis();
        boolean animating = false;
        if (mCurrDrawable != null) {
            if (mEnterAnimationEnd != 0) {
                if (mEnterAnimationEnd <= now) {
                    mCurrDrawable.mutate().setAlpha(mAlpha);
                    mEnterAnimationEnd = 0;
                } else {
                    int animAlpha = (int)((mEnterAnimationEnd-now)*255)
                            / mDrawableContainerState.mEnterFadeDuration;
                    if (DEBUG) android.util.Log.i(TAG, toString() + " cur alpha " + animAlpha);
                    mCurrDrawable.mutate().setAlpha(((255-animAlpha)*mAlpha)/255);
                    animating = true;
                }
            }
        } else {
            mEnterAnimationEnd = 0;
        }
        if (mLastDrawable != null) {
            if (mExitAnimationEnd != 0) {
                if (mExitAnimationEnd <= now) {
                    mLastDrawable.setVisible(false, false);
                    mLastDrawable = null;
                    mLastIndex = -1;
                    mExitAnimationEnd = 0;
                } else {
                    int animAlpha = (int)((mExitAnimationEnd-now)*255)
                            / mDrawableContainerState.mExitFadeDuration;
                    if (DEBUG) android.util.Log.i(TAG, toString() + " last alpha " + animAlpha);
                    mLastDrawable.mutate().setAlpha((animAlpha*mAlpha)/255);
                    animating = true;
                }
            }
        } else {
            mExitAnimationEnd = 0;
        }

        if (schedule && animating) {
            scheduleSelf(mAnimationRunnable, now + 1000 / 60);
        }
    
public voidapplyTheme(android.content.res.Resources.Theme theme)

        mDrawableContainerState.applyTheme(theme);
    
public booleancanApplyTheme()

        return mDrawableContainerState.canApplyTheme();
    
public voidclearMutated()

hide

        super.clearMutated();
        mDrawableContainerState.clearMutated();
        mMutated = false;
    
android.graphics.drawable.DrawableContainer$DrawableContainerStatecloneConstantState()
Returns a shallow copy of the container's constant state to be used as the base state for {@link #mutate()}.

return
a shallow copy of the constant state

        return mDrawableContainerState;
    
public voiddraw(android.graphics.Canvas canvas)


    // overrides from Drawable

    
        
        if (mCurrDrawable != null) {
            mCurrDrawable.draw(canvas);
        }
        if (mLastDrawable != null) {
            mLastDrawable.draw(canvas);
        }
    
public intgetAlpha()

        return mAlpha;
    
public intgetChangingConfigurations()

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

        if (mDrawableContainerState.canConstantState()) {
            mDrawableContainerState.mChangingConfigurations = getChangingConfigurations();
            return mDrawableContainerState;
        }
        return null;
    
public DrawablegetCurrent()

        return mCurrDrawable;
    
public intgetCurrentIndex()

hide

        return mCurIndex;
    
public voidgetHotspotBounds(android.graphics.Rect outRect)

hide

        if (mHotspotBounds != null) {
            outRect.set(mHotspotBounds);
        } else {
            super.getHotspotBounds(outRect);
        }
    
public intgetIntrinsicHeight()

        if (mDrawableContainerState.isConstantSize()) {
            return mDrawableContainerState.getConstantHeight();
        }
        return mCurrDrawable != null ? mCurrDrawable.getIntrinsicHeight() : -1;
    
public intgetIntrinsicWidth()

        if (mDrawableContainerState.isConstantSize()) {
            return mDrawableContainerState.getConstantWidth();
        }
        return mCurrDrawable != null ? mCurrDrawable.getIntrinsicWidth() : -1;
    
public intgetMinimumHeight()

        if (mDrawableContainerState.isConstantSize()) {
            return mDrawableContainerState.getConstantMinimumHeight();
        }
        return mCurrDrawable != null ? mCurrDrawable.getMinimumHeight() : 0;
    
public intgetMinimumWidth()

        if (mDrawableContainerState.isConstantSize()) {
            return mDrawableContainerState.getConstantMinimumWidth();
        }
        return mCurrDrawable != null ? mCurrDrawable.getMinimumWidth() : 0;
    
public intgetOpacity()

        return mCurrDrawable == null || !mCurrDrawable.isVisible() ? PixelFormat.TRANSPARENT :
                mDrawableContainerState.getOpacity();
    
public android.graphics.InsetsgetOpticalInsets()

hide

        if (mCurrDrawable != null) {
            return mCurrDrawable.getOpticalInsets();
        }
        return Insets.NONE;
    
public voidgetOutline(android.graphics.Outline outline)

        if (mCurrDrawable != null) {
            mCurrDrawable.getOutline(outline);
        }
    
public booleangetPadding(android.graphics.Rect padding)

        final Rect r = mDrawableContainerState.getConstantPadding();
        boolean result;
        if (r != null) {
            padding.set(r);
            result = (r.left | r.top | r.bottom | r.right) != 0;
        } else {
            if (mCurrDrawable != null) {
                result = mCurrDrawable.getPadding(padding);
            } else {
                result = super.getPadding(padding);
            }
        }
        if (needsMirroring()) {
            final int left = padding.left;
            final int right = padding.right;
            padding.left = right;
            padding.right = left;
        }
        return result;
    
private voidinitializeDrawableForDisplay(Drawable d)
Initializes a drawable for display in this container.

param
d The drawable to initialize.

        d.mutate();

        if (mDrawableContainerState.mEnterFadeDuration <= 0 && mHasAlpha) {
            d.setAlpha(mAlpha);
        }

        if (mDrawableContainerState.mHasColorFilter) {
            // Color filter always overrides tint.
            d.setColorFilter(mDrawableContainerState.mColorFilter);
        } else {
            if (mDrawableContainerState.mHasTintList) {
                d.setTintList(mDrawableContainerState.mTintList);
            }
            if (mDrawableContainerState.mHasTintMode) {
                d.setTintMode(mDrawableContainerState.mTintMode);
            }
        }

        d.setVisible(isVisible(), true);
        d.setDither(mDrawableContainerState.mDither);
        d.setState(getState());
        d.setLevel(getLevel());
        d.setBounds(getBounds());
        d.setLayoutDirection(getLayoutDirection());
        d.setAutoMirrored(mDrawableContainerState.mAutoMirrored);

        final Rect hotspotBounds = mHotspotBounds;
        if (hotspotBounds != null) {
            d.setHotspotBounds(hotspotBounds.left, hotspotBounds.top,
                    hotspotBounds.right, hotspotBounds.bottom);
        }
    
public voidinvalidateDrawable(Drawable who)

        if (who == mCurrDrawable && getCallback() != null) {
            getCallback().invalidateDrawable(this);
        }
    
public booleanisAutoMirrored()

        return mDrawableContainerState.mAutoMirrored;
    
public booleanisStateful()

        return mDrawableContainerState.isStateful();
    
public voidjumpToCurrentState()

        boolean changed = false;
        if (mLastDrawable != null) {
            mLastDrawable.jumpToCurrentState();
            mLastDrawable = null;
            mLastIndex = -1;
            changed = true;
        }
        if (mCurrDrawable != null) {
            mCurrDrawable.jumpToCurrentState();
            if (mHasAlpha) {
                mCurrDrawable.mutate().setAlpha(mAlpha);
            }
        }
        if (mExitAnimationEnd != 0) {
            mExitAnimationEnd = 0;
            changed = true;
        }
        if (mEnterAnimationEnd != 0) {
            mEnterAnimationEnd = 0;
            changed = true;
        }
        if (changed) {
            invalidateSelf();
        }
    
public Drawablemutate()

        if (!mMutated && super.mutate() == this) {
            final DrawableContainerState clone = cloneConstantState();
            clone.mutate();
            setConstantState(clone);
            mMutated = true;
        }
        return this;
    
private booleanneedsMirroring()

        return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
    
protected voidonBoundsChange(android.graphics.Rect bounds)

        if (mLastDrawable != null) {
            mLastDrawable.setBounds(bounds);
        }
        if (mCurrDrawable != null) {
            mCurrDrawable.setBounds(bounds);
        }
    
protected booleanonLevelChange(int level)

        if (mLastDrawable != null) {
            return mLastDrawable.setLevel(level);
        }
        if (mCurrDrawable != null) {
            return mCurrDrawable.setLevel(level);
        }
        return false;
    
protected booleanonStateChange(int[] state)

        if (mLastDrawable != null) {
            return mLastDrawable.setState(state);
        }
        if (mCurrDrawable != null) {
            return mCurrDrawable.setState(state);
        }
        return false;
    
public voidscheduleDrawable(Drawable who, java.lang.Runnable what, long when)

        if (who == mCurrDrawable && getCallback() != null) {
            getCallback().scheduleDrawable(this, what, when);
        }
    
public booleanselectDrawable(int idx)

        if (idx == mCurIndex) {
            return false;
        }

        final long now = SystemClock.uptimeMillis();

        if (DEBUG) android.util.Log.i(TAG, toString() + " from " + mCurIndex + " to " + idx
                + ": exit=" + mDrawableContainerState.mExitFadeDuration
                + " enter=" + mDrawableContainerState.mEnterFadeDuration);

        if (mDrawableContainerState.mExitFadeDuration > 0) {
            if (mLastDrawable != null) {
                mLastDrawable.setVisible(false, false);
            }
            if (mCurrDrawable != null) {
                mLastDrawable = mCurrDrawable;
                mLastIndex = mCurIndex;
                mExitAnimationEnd = now + mDrawableContainerState.mExitFadeDuration;
            } else {
                mLastDrawable = null;
                mLastIndex = -1;
                mExitAnimationEnd = 0;
            }
        } else if (mCurrDrawable != null) {
            mCurrDrawable.setVisible(false, false);
        }

        if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
            final Drawable d = mDrawableContainerState.getChild(idx);
            mCurrDrawable = d;
            mCurIndex = idx;
            if (d != null) {
                if (mDrawableContainerState.mEnterFadeDuration > 0) {
                    mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration;
                }
                initializeDrawableForDisplay(d);
            }
        } else {
            mCurrDrawable = null;
            mCurIndex = -1;
        }

        if (mEnterAnimationEnd != 0 || mExitAnimationEnd != 0) {
            if (mAnimationRunnable == null) {
                mAnimationRunnable = new Runnable() {
                    @Override public void run() {
                        animate(true);
                        invalidateSelf();
                    }
                };
            } else {
                unscheduleSelf(mAnimationRunnable);
            }
            // Compute first frame and schedule next animation.
            animate(true);
        }

        invalidateSelf();

        return true;
    
public voidsetAlpha(int alpha)

        if (!mHasAlpha || mAlpha != alpha) {
            mHasAlpha = true;
            mAlpha = alpha;
            if (mCurrDrawable != null) {
                if (mEnterAnimationEnd == 0) {
                    mCurrDrawable.mutate().setAlpha(alpha);
                } else {
                    animate(false);
                }
            }
        }
    
public voidsetAutoMirrored(boolean mirrored)

        if (mDrawableContainerState.mAutoMirrored != mirrored) {
            mDrawableContainerState.mAutoMirrored = mirrored;
            if (mCurrDrawable != null) {
                mCurrDrawable.mutate().setAutoMirrored(mDrawableContainerState.mAutoMirrored);
            }
        }
    
public voidsetColorFilter(android.graphics.ColorFilter cf)

        mDrawableContainerState.mHasColorFilter = (cf != null);

        if (mDrawableContainerState.mColorFilter != cf) {
            mDrawableContainerState.mColorFilter = cf;

            if (mCurrDrawable != null) {
                mCurrDrawable.mutate().setColorFilter(cf);
            }
        }
    
protected voidsetConstantState(android.graphics.drawable.DrawableContainer$DrawableContainerState state)

        mDrawableContainerState = state;

        // The locally cached drawables may have changed.
        if (mCurIndex >= 0) {
            mCurrDrawable = state.getChild(mCurIndex);
            if (mCurrDrawable != null) {
                initializeDrawableForDisplay(mCurrDrawable);
            }
        }

        // Clear out the last drawable. We don't have enough information to
        // propagate local state from the past.
        mLastIndex = -1;
        mLastDrawable = null;
    
public voidsetCurrentIndex(int index)

hide

        selectDrawable(index);
    
public voidsetDither(boolean dither)

        if (mDrawableContainerState.mDither != dither) {
            mDrawableContainerState.mDither = dither;
            if (mCurrDrawable != null) {
                mCurrDrawable.mutate().setDither(mDrawableContainerState.mDither);
            }
        }
    
public voidsetEnterFadeDuration(int ms)
Change the global fade duration when a new drawable is entering the scene.

param
ms The amount of time to fade in milliseconds.

        mDrawableContainerState.mEnterFadeDuration = ms;
    
public voidsetExitFadeDuration(int ms)
Change the global fade duration when a new drawable is leaving the scene.

param
ms The amount of time to fade in milliseconds.

        mDrawableContainerState.mExitFadeDuration = ms;
    
public voidsetHotspot(float x, float y)

        if (mCurrDrawable != null) {
            mCurrDrawable.setHotspot(x, y);
        }
    
public voidsetHotspotBounds(int left, int top, int right, int bottom)

        if (mHotspotBounds == null) {
            mHotspotBounds = new Rect(left, top, bottom, right);
        } else {
            mHotspotBounds.set(left, top, bottom, right);
        }

        if (mCurrDrawable != null) {
            mCurrDrawable.setHotspotBounds(left, top, right, bottom);
        }
    
public voidsetTintList(android.content.res.ColorStateList tint)

        mDrawableContainerState.mHasTintList = true;

        if (mDrawableContainerState.mTintList != tint) {
            mDrawableContainerState.mTintList = tint;

            if (mCurrDrawable != null) {
                mCurrDrawable.mutate().setTintList(tint);
            }
        }
    
public voidsetTintMode(android.graphics.PorterDuff.Mode tintMode)

        mDrawableContainerState.mHasTintMode = true;

        if (mDrawableContainerState.mTintMode != tintMode) {
            mDrawableContainerState.mTintMode = tintMode;

            if (mCurrDrawable != null) {
                mCurrDrawable.mutate().setTintMode(tintMode);
            }
        }
    
public booleansetVisible(boolean visible, boolean restart)

        boolean changed = super.setVisible(visible, restart);
        if (mLastDrawable != null) {
            mLastDrawable.setVisible(visible, restart);
        }
        if (mCurrDrawable != null) {
            mCurrDrawable.setVisible(visible, restart);
        }
        return changed;
    
public voidunscheduleDrawable(Drawable who, java.lang.Runnable what)

        if (who == mCurrDrawable && getCallback() != null) {
            getCallback().unscheduleDrawable(this, what);
        }