FileDocCategorySizeDatePackage
StyledCornersBitmapDrawable.javaAPI DocAndroid 5.1 API16899Thu Mar 12 22:22:50 GMT 2015com.android.bitmap.drawable

StyledCornersBitmapDrawable

public class StyledCornersBitmapDrawable extends ExtendedBitmapDrawable
A custom ExtendedBitmapDrawable that styles the corners in configurable ways. All four corners can be configured as {@link #CORNER_STYLE_SHARP}, {@link #CORNER_STYLE_ROUND}, or {@link #CORNER_STYLE_FLAP}. This is accomplished applying a non-rectangular clip applied to the canvas. A border is draw that conforms to the styled corners. {@link #CORNER_STYLE_FLAP} corners have a colored flap drawn within the bounds.

Fields Summary
public static final int
CORNER_STYLE_SHARP
public static final int
CORNER_STYLE_ROUND
public static final int
CORNER_STYLE_FLAP
private static final int
START_RIGHT
private static final int
START_BOTTOM
private static final int
START_LEFT
private static final int
START_TOP
private static final int
QUARTER_CIRCLE
private static final android.graphics.RectF
sRectF
private final android.graphics.Paint
mFlapPaint
private final android.graphics.Paint
mBorderPaint
private final android.graphics.Paint
mCompatibilityModeBackgroundPaint
private final android.graphics.Path
mClipPath
private final android.graphics.Path
mCompatibilityModePath
private final float
mCornerRoundRadius
private final float
mCornerFlapSide
private int
mTopLeftCornerStyle
private int
mTopRightCornerStyle
private int
mBottomRightCornerStyle
private int
mBottomLeftCornerStyle
private int
mScrimColor
private float
mBorderWidth
private boolean
mIsCompatibilityMode
Constructors Summary
public StyledCornersBitmapDrawable(android.content.res.Resources res, com.android.bitmap.BitmapCache cache, boolean limitDensity, ExtendedOptions opts, float cornerRoundRadius, float cornerFlapSide)
Create a new StyledCornersBitmapDrawable.


             
        
                 
              
        super(res, cache, limitDensity, opts);

        mCornerRoundRadius = cornerRoundRadius;
        mCornerFlapSide = cornerFlapSide;

        mFlapPaint.setColor(Color.TRANSPARENT);
        mFlapPaint.setStyle(Style.FILL);
        mFlapPaint.setAntiAlias(true);

        mBorderPaint.setColor(Color.TRANSPARENT);
        mBorderPaint.setStyle(Style.STROKE);
        mBorderPaint.setStrokeWidth(mBorderWidth);
        mBorderPaint.setAntiAlias(true);

        mCompatibilityModeBackgroundPaint.setColor(Color.TRANSPARENT);
        mCompatibilityModeBackgroundPaint.setStyle(Style.FILL);
        mCompatibilityModeBackgroundPaint.setAntiAlias(true);

        mScrimColor = Color.TRANSPARENT;
    
Methods Summary
public voiddraw(android.graphics.Canvas canvas)
Override draw(android.graphics.Canvas) instead of {@link #onDraw(android.graphics.Canvas)} to clip all the drawable layers.

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

        // Clip to path.
        if (!mIsCompatibilityMode) {
            canvas.save();
            canvas.clipPath(mClipPath);
        }

        // Draw parent within path.
        super.draw(canvas);

        // Draw scrim on top of parent.
        canvas.drawColor(mScrimColor);

        // Draw flaps.
        float left = bounds.left + mBorderWidth / 2;
        float top = bounds.top + mBorderWidth / 2;
        float right = bounds.right - mBorderWidth / 2;
        float bottom = bounds.bottom - mBorderWidth / 2;
        RectF flapCornerRectF = sRectF;
        flapCornerRectF.set(0, 0, mCornerFlapSide + mCornerRoundRadius,
                mCornerFlapSide + mCornerRoundRadius);

        if (mTopLeftCornerStyle == CORNER_STYLE_FLAP) {
            flapCornerRectF.offsetTo(left, top);
            canvas.drawRoundRect(flapCornerRectF, mCornerRoundRadius,
                    mCornerRoundRadius, mFlapPaint);
        }
        if (mTopRightCornerStyle == CORNER_STYLE_FLAP) {
            flapCornerRectF.offsetTo(right - mCornerFlapSide, top);
            canvas.drawRoundRect(flapCornerRectF, mCornerRoundRadius,
                    mCornerRoundRadius, mFlapPaint);
        }
        if (mBottomRightCornerStyle == CORNER_STYLE_FLAP) {
            flapCornerRectF.offsetTo(right - mCornerFlapSide, bottom - mCornerFlapSide);
            canvas.drawRoundRect(flapCornerRectF, mCornerRoundRadius,
                    mCornerRoundRadius, mFlapPaint);
        }
        if (mBottomLeftCornerStyle == CORNER_STYLE_FLAP) {
            flapCornerRectF.offsetTo(left, bottom - mCornerFlapSide);
            canvas.drawRoundRect(flapCornerRectF, mCornerRoundRadius,
                    mCornerRoundRadius, mFlapPaint);
        }

        if (!mIsCompatibilityMode) {
            canvas.restore();
        }

        if (mIsCompatibilityMode) {
            drawFakeCornersForCompatibilityMode(canvas);
        }

        // Draw border around path.
        canvas.drawPath(mClipPath, mBorderPaint);
    
protected voiddrawFakeCornersForCompatibilityMode(android.graphics.Canvas canvas)

        final Rect bounds = getBounds();

        float left = bounds.left;
        float top = bounds.top;
        float right = bounds.right;
        float bottom = bounds.bottom;

        // Draw fake round corners.
        RectF fakeCornerRectF = sRectF;
        fakeCornerRectF.set(0, 0, mCornerRoundRadius * 2, mCornerRoundRadius * 2);
        if (mTopLeftCornerStyle == CORNER_STYLE_ROUND) {
            fakeCornerRectF.offsetTo(left, top);
            mCompatibilityModePath.rewind();
            mCompatibilityModePath.moveTo(left, top);
            mCompatibilityModePath.lineTo(left + mCornerRoundRadius, top);
            mCompatibilityModePath.arcTo(fakeCornerRectF, START_TOP, -QUARTER_CIRCLE);
            mCompatibilityModePath.close();
            canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint);
        }
        if (mTopRightCornerStyle == CORNER_STYLE_ROUND) {
            fakeCornerRectF.offsetTo(right - fakeCornerRectF.width(), top);
            mCompatibilityModePath.rewind();
            mCompatibilityModePath.moveTo(right, top);
            mCompatibilityModePath.lineTo(right, top + mCornerRoundRadius);
            mCompatibilityModePath.arcTo(fakeCornerRectF, START_RIGHT, -QUARTER_CIRCLE);
            mCompatibilityModePath.close();
            canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint);
        }
        if (mBottomRightCornerStyle == CORNER_STYLE_ROUND) {
            fakeCornerRectF
                    .offsetTo(right - fakeCornerRectF.width(), bottom - fakeCornerRectF.height());
            mCompatibilityModePath.rewind();
            mCompatibilityModePath.moveTo(right, bottom);
            mCompatibilityModePath.lineTo(right - mCornerRoundRadius, bottom);
            mCompatibilityModePath.arcTo(fakeCornerRectF, START_BOTTOM, -QUARTER_CIRCLE);
            mCompatibilityModePath.close();
            canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint);
        }
        if (mBottomLeftCornerStyle == CORNER_STYLE_ROUND) {
            fakeCornerRectF.offsetTo(left, bottom - fakeCornerRectF.height());
            mCompatibilityModePath.rewind();
            mCompatibilityModePath.moveTo(left, bottom);
            mCompatibilityModePath.lineTo(left, bottom - mCornerRoundRadius);
            mCompatibilityModePath.arcTo(fakeCornerRectF, START_LEFT, -QUARTER_CIRCLE);
            mCompatibilityModePath.close();
            canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint);
        }

        // Draw fake flap corners.
        if (mTopLeftCornerStyle == CORNER_STYLE_FLAP) {
            mCompatibilityModePath.rewind();
            mCompatibilityModePath.moveTo(left, top);
            mCompatibilityModePath.lineTo(left + mCornerFlapSide, top);
            mCompatibilityModePath.lineTo(left, top + mCornerFlapSide);
            mCompatibilityModePath.close();
            canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint);
        }
        if (mTopRightCornerStyle == CORNER_STYLE_FLAP) {
            mCompatibilityModePath.rewind();
            mCompatibilityModePath.moveTo(right, top);
            mCompatibilityModePath.lineTo(right, top + mCornerFlapSide);
            mCompatibilityModePath.lineTo(right - mCornerFlapSide, top);
            mCompatibilityModePath.close();
            canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint);
        }
        if (mBottomRightCornerStyle == CORNER_STYLE_FLAP) {
            mCompatibilityModePath.rewind();
            mCompatibilityModePath.moveTo(right, bottom);
            mCompatibilityModePath.lineTo(right - mCornerFlapSide, bottom);
            mCompatibilityModePath.lineTo(right, bottom - mCornerFlapSide);
            mCompatibilityModePath.close();
            canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint);
        }
        if (mBottomLeftCornerStyle == CORNER_STYLE_FLAP) {
            mCompatibilityModePath.rewind();
            mCompatibilityModePath.moveTo(left, bottom);
            mCompatibilityModePath.lineTo(left, bottom - mCornerFlapSide);
            mCompatibilityModePath.lineTo(left + mCornerFlapSide, bottom);
            mCompatibilityModePath.close();
            canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint);
        }
    
public intgetFlapColor()
Get the flap color for all corners that have style {@link #CORNER_STYLE_SHARP}.

        return mFlapPaint.getColor();
    
public intgetScrimColor()
Get the color of the scrim that is drawn over the contents, but under the flaps and borders.

        return mScrimColor;
    
protected voidonBoundsChange(android.graphics.Rect bounds)

        super.onBoundsChange(bounds);

        recalculatePath();
    
private voidrecalculatePath()

        Rect bounds = getBounds();

        if (bounds.isEmpty()) {
            return;
        }

        // Setup.
        float left = bounds.left + mBorderWidth / 2;
        float top = bounds.top + mBorderWidth / 2;
        float right = bounds.right - mBorderWidth / 2;
        float bottom = bounds.bottom - mBorderWidth / 2;
        RectF roundedCornerRectF = sRectF;
        roundedCornerRectF.set(0, 0, 2 * mCornerRoundRadius, 2 * mCornerRoundRadius);
        mClipPath.rewind();

        switch (mTopLeftCornerStyle) {
            case CORNER_STYLE_SHARP:
                mClipPath.moveTo(left, top);
                break;
            case CORNER_STYLE_ROUND:
                roundedCornerRectF.offsetTo(left, top);
                mClipPath.arcTo(roundedCornerRectF, START_LEFT, QUARTER_CIRCLE);
                break;
            case CORNER_STYLE_FLAP:
                mClipPath.moveTo(left, top - mCornerFlapSide);
                mClipPath.lineTo(left + mCornerFlapSide, top);
                break;
        }

        switch (mTopRightCornerStyle) {
            case CORNER_STYLE_SHARP:
                mClipPath.lineTo(right, top);
                break;
            case CORNER_STYLE_ROUND:
                roundedCornerRectF.offsetTo(right - roundedCornerRectF.width(), top);
                mClipPath.arcTo(roundedCornerRectF, START_TOP, QUARTER_CIRCLE);
                break;
            case CORNER_STYLE_FLAP:
                mClipPath.lineTo(right - mCornerFlapSide, top);
                mClipPath.lineTo(right, top + mCornerFlapSide);
                break;
        }

        switch (mBottomRightCornerStyle) {
            case CORNER_STYLE_SHARP:
                mClipPath.lineTo(right, bottom);
                break;
            case CORNER_STYLE_ROUND:
                roundedCornerRectF.offsetTo(right - roundedCornerRectF.width(),
                        bottom - roundedCornerRectF.height());
                mClipPath.arcTo(roundedCornerRectF, START_RIGHT, QUARTER_CIRCLE);
                break;
            case CORNER_STYLE_FLAP:
                mClipPath.lineTo(right, bottom - mCornerFlapSide);
                mClipPath.lineTo(right - mCornerFlapSide, bottom);
                break;
        }

        switch (mBottomLeftCornerStyle) {
            case CORNER_STYLE_SHARP:
                mClipPath.lineTo(left, bottom);
                break;
            case CORNER_STYLE_ROUND:
                roundedCornerRectF.offsetTo(left, bottom - roundedCornerRectF.height());
                mClipPath.arcTo(roundedCornerRectF, START_BOTTOM, QUARTER_CIRCLE);
                break;
            case CORNER_STYLE_FLAP:
                mClipPath.lineTo(left + mCornerFlapSide, bottom);
                mClipPath.lineTo(left, bottom - mCornerFlapSide);
                break;
        }

        // Finish.
        mClipPath.close();
    
public voidsetBorderColor(int color)
Set the border stroke color of this drawable. Set to {@link Color#TRANSPARENT} to disable.

        final boolean changed = mBorderPaint.getColor() != color;
        mBorderPaint.setColor(color);

        if (changed) {
            invalidateSelf();
        }
    
public voidsetBorderWidth(float borderWidth)
Set the border stroke width of this drawable.

        final boolean changed = mBorderPaint.getStrokeWidth() != borderWidth;
        mBorderPaint.setStrokeWidth(borderWidth);
        mBorderWidth = borderWidth;

        if (changed) {
            invalidateSelf();
        }
    
public voidsetCompatibilityMode(boolean isCompatibilityMode)
Sets whether we should work around an issue introduced in Android 4.4.3, where a WebView can corrupt the stencil buffer of the canvas when the canvas is clipped using a non-rectangular Path.

        boolean changed = mIsCompatibilityMode != isCompatibilityMode;
        mIsCompatibilityMode = isCompatibilityMode;

        if (changed) {
            invalidateSelf();
        }
    
public voidsetCompatibilityModeBackgroundColor(int color)
Sets the color of the container that this drawable is in. The given color will be used in {@link #setCompatibilityMode compatibility mode} to draw fake corners to emulate clipped corners.

        boolean changed = mCompatibilityModeBackgroundPaint.getColor() != color;
        mCompatibilityModeBackgroundPaint.setColor(color);

        if (changed) {
            invalidateSelf();
        }
    
public voidsetCornerStyles(int topLeft, int topRight, int bottomRight, int bottomLeft)
Set the corner styles for all four corners

        boolean changed = mTopLeftCornerStyle != topLeft
                || mTopRightCornerStyle != topRight
                || mBottomRightCornerStyle != bottomRight
                || mBottomLeftCornerStyle != bottomLeft;

        mTopLeftCornerStyle = topLeft;
        mTopRightCornerStyle = topRight;
        mBottomRightCornerStyle = bottomRight;
        mBottomLeftCornerStyle = bottomLeft;

        if (changed) {
            recalculatePath();
        }
    
public voidsetFlapColor(int flapColor)
Set the flap color for all corners that have style {@link #CORNER_STYLE_SHARP}. Use {@link android.graphics.Color#TRANSPARENT} to disable flap colors.

        boolean changed = mFlapPaint.getColor() != flapColor;
        mFlapPaint.setColor(flapColor);

        if (changed) {
            invalidateSelf();
        }
    
public voidsetScrimColor(int color)
Set the color of the scrim that is drawn over the contents, but under the flaps and borders. Use {@link android.graphics.Color#TRANSPARENT} to disable the scrim.

        boolean changed = mScrimColor != color;
        mScrimColor = color;

        if (changed) {
            invalidateSelf();
        }