FileDocCategorySizeDatePackage
NinePatchDrawable.javaAPI DocAndroid 5.1 API23698Thu Mar 12 22:22:30 GMT 2015android.graphics.drawable

NinePatchDrawable

public class NinePatchDrawable extends Drawable
A resizeable bitmap, with stretchable areas that you define. This type of image is defined in a .png file with a special format.

Developer Guides

For more information about how to use a NinePatchDrawable, read the Canvas and Drawables developer guide. For information about creating a NinePatch image file using the draw9patch tool, see the Draw 9-patch tool guide.

Fields Summary
private static final boolean
DEFAULT_DITHER
private NinePatchState
mNinePatchState
private android.graphics.NinePatch
mNinePatch
private android.graphics.PorterDuffColorFilter
mTintFilter
private android.graphics.Rect
mPadding
private android.graphics.Insets
mOpticalInsets
private android.graphics.Paint
mPaint
private boolean
mMutated
private int
mTargetDensity
private int
mBitmapWidth
private int
mBitmapHeight
Constructors Summary
NinePatchDrawable()


     
        mNinePatchState = new NinePatchState();
    
public NinePatchDrawable(android.graphics.Bitmap bitmap, byte[] chunk, android.graphics.Rect padding, String srcName)
Create drawable from raw nine-patch data, not dealing with density.

deprecated
Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)} to ensure that the drawable has correctly set its target density.

        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null);
    
public NinePatchDrawable(android.content.res.Resources res, android.graphics.Bitmap bitmap, byte[] chunk, android.graphics.Rect padding, String srcName)
Create drawable from raw nine-patch data, setting initial target density based on the display metrics of the resources.

        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
        mNinePatchState.mTargetDensity = mTargetDensity;
    
public NinePatchDrawable(android.content.res.Resources res, android.graphics.Bitmap bitmap, byte[] chunk, android.graphics.Rect padding, android.graphics.Rect opticalInsets, String srcName)
Create drawable from raw nine-patch data, setting initial target density based on the display metrics of the resources.

hide

        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets),
                res);
        mNinePatchState.mTargetDensity = mTargetDensity;
    
private NinePatchDrawable(NinePatchState state, android.content.res.Resources res)
The one constructor to rule them all. This is called by all public constructors to set the state and initialize local properties.

        mNinePatchState = state;

        initializeWithState(mNinePatchState, res);
    
public NinePatchDrawable(android.graphics.NinePatch patch)
Create drawable from existing nine-patch, not dealing with density.

deprecated
Use {@link #NinePatchDrawable(Resources, NinePatch)} to ensure that the drawable has correctly set its target density.

        this(new NinePatchState(patch, new Rect()), null);
    
public NinePatchDrawable(android.content.res.Resources res, android.graphics.NinePatch patch)
Create drawable from existing nine-patch, setting initial target density based on the display metrics of the resources.

        this(new NinePatchState(patch, new Rect()), res);
        mNinePatchState.mTargetDensity = mTargetDensity;
    
Methods Summary
public voidapplyTheme(android.content.res.Resources.Theme t)

        super.applyTheme(t);

        final NinePatchState state = mNinePatchState;
        if (state == null || state.mThemeAttrs == null) {
            return;
        }

        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.NinePatchDrawable);
        try {
            updateStateFromTypedArray(a);
        } catch (XmlPullParserException e) {
            throw new RuntimeException(e);
        } finally {
            a.recycle();
        }
    
public booleancanApplyTheme()

        return mNinePatchState != null && mNinePatchState.mThemeAttrs != null;
    
public voidclearMutated()

hide

        super.clearMutated();
        mMutated = false;
    
private voidcomputeBitmapSize()

        final int sdensity = mNinePatch.getDensity();
        final int tdensity = mTargetDensity;
        if (sdensity == tdensity) {
            mBitmapWidth = mNinePatch.getWidth();
            mBitmapHeight = mNinePatch.getHeight();
            mOpticalInsets = mNinePatchState.mOpticalInsets;
        } else {
            mBitmapWidth = Bitmap.scaleFromDensity(mNinePatch.getWidth(), sdensity, tdensity);
            mBitmapHeight = Bitmap.scaleFromDensity(mNinePatch.getHeight(), sdensity, tdensity);
            if (mNinePatchState.mPadding != null && mPadding != null) {
                Rect dest = mPadding;
                Rect src = mNinePatchState.mPadding;
                if (dest == src) {
                    mPadding = dest = new Rect(src);
                }
                dest.left = Bitmap.scaleFromDensity(src.left, sdensity, tdensity);
                dest.top = Bitmap.scaleFromDensity(src.top, sdensity, tdensity);
                dest.right = Bitmap.scaleFromDensity(src.right, sdensity, tdensity);
                dest.bottom = Bitmap.scaleFromDensity(src.bottom, sdensity, tdensity);
            }
            mOpticalInsets = scaleFromDensity(mNinePatchState.mOpticalInsets, sdensity, tdensity);
        }
    
public voiddraw(android.graphics.Canvas canvas)

        final Rect bounds = getBounds();

        final boolean clearColorFilter;
        if (mTintFilter != null && getPaint().getColorFilter() == null) {
            mPaint.setColorFilter(mTintFilter);
            clearColorFilter = true;
        } else {
            clearColorFilter = false;
        }

        final boolean needsMirroring = needsMirroring();
        if (needsMirroring) {
            // Mirror the 9patch
            canvas.translate(bounds.right - bounds.left, 0);
            canvas.scale(-1.0f, 1.0f);
        }

        final int restoreAlpha;
        if (mNinePatchState.mBaseAlpha != 1.0f) {
            restoreAlpha = mPaint.getAlpha();
            mPaint.setAlpha((int) (restoreAlpha * mNinePatchState.mBaseAlpha + 0.5f));
        } else {
            restoreAlpha = -1;
        }

        mNinePatch.draw(canvas, bounds, mPaint);

        if (clearColorFilter) {
            mPaint.setColorFilter(null);
        }

        if (restoreAlpha >= 0) {
            mPaint.setAlpha(restoreAlpha);
        }
    
public intgetAlpha()

        if (mPaint == null) {
            // Fast common case -- normal alpha.
            return 0xFF;
        }
        return getPaint().getAlpha();
    
public intgetChangingConfigurations()

        return super.getChangingConfigurations() | mNinePatchState.mChangingConfigurations;
    
public ConstantStategetConstantState()

        mNinePatchState.mChangingConfigurations = getChangingConfigurations();
        return mNinePatchState;
    
public intgetIntrinsicHeight()
Retrieves the height of the source .png file (before resizing).

        return mBitmapHeight;
    
public intgetIntrinsicWidth()
Retrieves the width of the source .png file (before resizing).

        return mBitmapWidth;
    
public intgetMinimumHeight()

        return mBitmapHeight;
    
public intgetMinimumWidth()

        return mBitmapWidth;
    
public intgetOpacity()
Returns a {@link android.graphics.PixelFormat graphics.PixelFormat} value of OPAQUE or TRANSLUCENT.

        return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255) ?
                PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
    
public android.graphics.InsetsgetOpticalInsets()

hide

        if (needsMirroring()) {
            return Insets.of(mOpticalInsets.right, mOpticalInsets.top,
                    mOpticalInsets.left, mOpticalInsets.bottom);
        } else {
            return mOpticalInsets;
        }
    
public voidgetOutline(android.graphics.Outline outline)

        final Rect bounds = getBounds();
        if (bounds.isEmpty()) return;

        if (mNinePatchState != null) {
            NinePatch.InsetStruct insets = mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets();
            if (insets != null) {
                final Rect outlineInsets = insets.outlineRect;
                outline.setRoundRect(bounds.left + outlineInsets.left,
                        bounds.top + outlineInsets.top,
                        bounds.right - outlineInsets.right,
                        bounds.bottom - outlineInsets.bottom,
                        insets.outlineRadius);
                outline.setAlpha(insets.outlineAlpha * (getAlpha() / 255.0f));
                return;
            }
        }
        super.getOutline(outline);
    
public booleangetPadding(android.graphics.Rect padding)

        final Rect scaledPadding = mPadding;
        if (scaledPadding != null) {
            if (needsMirroring()) {
                padding.set(scaledPadding.right, scaledPadding.top,
                        scaledPadding.left, scaledPadding.bottom);
            } else {
                padding.set(scaledPadding);
            }
            return (padding.left | padding.top | padding.right | padding.bottom) != 0;
        }
        return false;
    
public android.graphics.PaintgetPaint()

        if (mPaint == null) {
            mPaint = new Paint();
            mPaint.setDither(DEFAULT_DITHER);
        }
        return mPaint;
    
public android.graphics.RegiongetTransparentRegion()

        return mNinePatch.getTransparentRegion(getBounds());
    
public voidinflate(android.content.res.Resources r, org.xmlpull.v1.XmlPullParser parser, android.util.AttributeSet attrs, android.content.res.Resources.Theme theme)

        super.inflate(r, parser, attrs, theme);

        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.NinePatchDrawable);
        updateStateFromTypedArray(a);
        a.recycle();
    
private voidinitializeWithState(android.graphics.drawable.NinePatchDrawable$NinePatchState state, android.content.res.Resources res)
Initializes local dynamic properties from state.

        if (res != null) {
            mTargetDensity = res.getDisplayMetrics().densityDpi;
        } else {
            mTargetDensity = state.mTargetDensity;
        }

        // If we can, avoid calling any methods that initialize Paint.
        if (state.mDither != DEFAULT_DITHER) {
            setDither(state.mDither);
        }

        // Make a local copy of the padding.
        if (state.mPadding != null) {
            mPadding = new Rect(state.mPadding);
        }

        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
        setNinePatch(state.mNinePatch);
    
public booleanisAutoMirrored()

        return mNinePatchState.mAutoMirrored;
    
public booleanisStateful()

        final NinePatchState s = mNinePatchState;
        return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
    
public Drawablemutate()

        if (!mMutated && super.mutate() == this) {
            mNinePatchState = new NinePatchState(mNinePatchState);
            mNinePatch = mNinePatchState.mNinePatch;
            mMutated = true;
        }
        return this;
    
private booleanneedsMirroring()

        return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
    
protected booleanonStateChange(int[] stateSet)

        final NinePatchState state = mNinePatchState;
        if (state.mTint != null && state.mTintMode != null) {
            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
            return true;
        }

        return false;
    
private static android.graphics.InsetsscaleFromDensity(android.graphics.Insets insets, int sdensity, int tdensity)

        int left = Bitmap.scaleFromDensity(insets.left, sdensity, tdensity);
        int top = Bitmap.scaleFromDensity(insets.top, sdensity, tdensity);
        int right = Bitmap.scaleFromDensity(insets.right, sdensity, tdensity);
        int bottom = Bitmap.scaleFromDensity(insets.bottom, sdensity, tdensity);
        return Insets.of(left, top, right, bottom);
    
public voidsetAlpha(int alpha)

        if (mPaint == null && alpha == 0xFF) {
            // Fast common case -- leave at normal alpha.
            return;
        }
        getPaint().setAlpha(alpha);
        invalidateSelf();
    
public voidsetAutoMirrored(boolean mirrored)

        mNinePatchState.mAutoMirrored = mirrored;
    
public voidsetColorFilter(android.graphics.ColorFilter cf)

        if (mPaint == null && cf == null) {
            // Fast common case -- leave at no color filter.
            return;
        }
        getPaint().setColorFilter(cf);
        invalidateSelf();
    
public voidsetDither(boolean dither)

        //noinspection PointlessBooleanExpression
        if (mPaint == null && dither == DEFAULT_DITHER) {
            // Fast common case -- leave at default dither.
            return;
        }

        getPaint().setDither(dither);
        invalidateSelf();
    
public voidsetFilterBitmap(boolean filter)

        getPaint().setFilterBitmap(filter);
        invalidateSelf();
    
private voidsetNinePatch(android.graphics.NinePatch ninePatch)

        if (mNinePatch != ninePatch) {
            mNinePatch = ninePatch;
            if (ninePatch != null) {
                computeBitmapSize();
            } else {
                mBitmapWidth = mBitmapHeight = -1;
                mOpticalInsets = Insets.NONE;
            }
            invalidateSelf();
        }
    
public voidsetTargetDensity(android.graphics.Canvas canvas)
Set the density scale at which this drawable will be rendered. This method assumes the drawable will be rendered at the same density as the specified canvas.

param
canvas The Canvas from which the density scale must be obtained.
see
android.graphics.Bitmap#setDensity(int)
see
android.graphics.Bitmap#getDensity()

        setTargetDensity(canvas.getDensity());
    
public voidsetTargetDensity(android.util.DisplayMetrics metrics)
Set the density scale at which this drawable will be rendered.

param
metrics The DisplayMetrics indicating the density scale for this drawable.
see
android.graphics.Bitmap#setDensity(int)
see
android.graphics.Bitmap#getDensity()

        setTargetDensity(metrics.densityDpi);
    
public voidsetTargetDensity(int density)
Set the density at which this drawable will be rendered.

param
density The density scale for this drawable.
see
android.graphics.Bitmap#setDensity(int)
see
android.graphics.Bitmap#getDensity()

        if (density != mTargetDensity) {
            mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
            if (mNinePatch != null) {
                computeBitmapSize();
            }
            invalidateSelf();
        }
    
public voidsetTintList(android.content.res.ColorStateList tint)

        mNinePatchState.mTint = tint;
        mTintFilter = updateTintFilter(mTintFilter, tint, mNinePatchState.mTintMode);
        invalidateSelf();
    
public voidsetTintMode(android.graphics.PorterDuff.Mode tintMode)

        mNinePatchState.mTintMode = tintMode;
        mTintFilter = updateTintFilter(mTintFilter, mNinePatchState.mTint, tintMode);
        invalidateSelf();
    
private voidupdateStateFromTypedArray(android.content.res.TypedArray a)
Updates the constant state from the values in the typed array.

        final Resources r = a.getResources();
        final NinePatchState state = mNinePatchState;

        // Account for any configuration changes.
        state.mChangingConfigurations |= a.getChangingConfigurations();

        // Extract the theme attributes, if any.
        state.mThemeAttrs = a.extractThemeAttrs();

        state.mDither = a.getBoolean(R.styleable.NinePatchDrawable_dither, state.mDither);

        final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
        if (srcResId != 0) {
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inDither = !state.mDither;
            options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi;

            final Rect padding = new Rect();
            final Rect opticalInsets = new Rect();
            Bitmap bitmap = null;

            try {
                final TypedValue value = new TypedValue();
                final InputStream is = r.openRawResource(srcResId, value);

                bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);

                is.close();
            } catch (IOException e) {
                // Ignore
            }

            if (bitmap == null) {
                throw new XmlPullParserException(a.getPositionDescription() +
                        ": <nine-patch> requires a valid src attribute");
            } else if (bitmap.getNinePatchChunk() == null) {
                throw new XmlPullParserException(a.getPositionDescription() +
                        ": <nine-patch> requires a valid 9-patch source image");
            }

            bitmap.getOpticalInsets(opticalInsets);

            state.mNinePatch = new NinePatch(bitmap, bitmap.getNinePatchChunk());
            state.mPadding = padding;
            state.mOpticalInsets = Insets.of(opticalInsets);
        }

        state.mAutoMirrored = a.getBoolean(
                R.styleable.NinePatchDrawable_autoMirrored, state.mAutoMirrored);
        state.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, state.mBaseAlpha);

        final int tintMode = a.getInt(R.styleable.NinePatchDrawable_tintMode, -1);
        if (tintMode != -1) {
            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
        }

        final ColorStateList tint = a.getColorStateList(R.styleable.NinePatchDrawable_tint);
        if (tint != null) {
            state.mTint = tint;
        }

        // Update local properties.
        initializeWithState(state, r);

        // Push density applied by setNinePatchState into state.
        state.mTargetDensity = mTargetDensity;