StyledCornersBitmapDrawablepublic 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 void | draw(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 void | drawFakeCornersForCompatibilityMode(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 int | getFlapColor()Get the flap color for all corners that have style {@link #CORNER_STYLE_SHARP}.
return mFlapPaint.getColor();
| public int | getScrimColor()Get the color of the scrim that is drawn over the contents, but under the flaps and borders.
return mScrimColor;
| protected void | onBoundsChange(android.graphics.Rect bounds)
super.onBoundsChange(bounds);
recalculatePath();
| private void | recalculatePath()
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 void | setBorderColor(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 void | setBorderWidth(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 void | setCompatibilityMode(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 void | setCompatibilityModeBackgroundColor(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 void | setCornerStyles(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 void | setFlapColor(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 void | setScrimColor(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();
}
|
|