summaryrefslogtreecommitdiff
path: root/src/com/android/bitmap/drawable/StyledCornersBitmapDrawable.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/bitmap/drawable/StyledCornersBitmapDrawable.java')
-rw-r--r--src/com/android/bitmap/drawable/StyledCornersBitmapDrawable.java310
1 files changed, 310 insertions, 0 deletions
diff --git a/src/com/android/bitmap/drawable/StyledCornersBitmapDrawable.java b/src/com/android/bitmap/drawable/StyledCornersBitmapDrawable.java
new file mode 100644
index 0000000..d5d04b3
--- /dev/null
+++ b/src/com/android/bitmap/drawable/StyledCornersBitmapDrawable.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bitmap.drawable;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+import com.android.bitmap.BitmapCache;
+
+/**
+ * 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.
+ */
+public class StyledCornersBitmapDrawable extends ExtendedBitmapDrawable {
+
+ public static final int CORNER_STYLE_SHARP = 0;
+ public static final int CORNER_STYLE_ROUND = 1;
+ public static final int CORNER_STYLE_FLAP = 2;
+
+ private static final int START_RIGHT = 0;
+ private static final int START_BOTTOM = 90;
+ private static final int START_LEFT = 180;
+ private static final int START_TOP = 270;
+ private static final int QUARTER_CIRCLE = 90;
+ private static final RectF sRectF = new RectF();
+
+ private final Paint mFlapPaint = new Paint();
+ private final Paint mBorderPaint = new Paint();
+ private final Path mClipPath = new Path();
+ private final float mCornerRoundRadius;
+ private final float mCornerFlapSide;
+
+ private int mTopLeftCornerStyle = CORNER_STYLE_SHARP;
+ private int mTopRightCornerStyle = CORNER_STYLE_SHARP;
+ private int mBottomRightCornerStyle = CORNER_STYLE_SHARP;
+ private int mBottomLeftCornerStyle = CORNER_STYLE_SHARP;
+ private int mScrimColor;
+ private float mBorderWidth;
+
+ /**
+ * Create a new StyledCornersBitmapDrawable.
+ */
+ public StyledCornersBitmapDrawable(Resources res, BitmapCache cache,
+ boolean limitDensity, ExtendedOptions opts, float cornerRoundRadius,
+ float cornerFlapSide) {
+ super(res, cache, limitDensity, opts);
+
+ mCornerRoundRadius = cornerRoundRadius;
+ mCornerFlapSide = cornerFlapSide;
+
+ mFlapPaint.setColor(Color.TRANSPARENT);
+ mFlapPaint.setStyle(Style.FILL);
+
+ mBorderPaint.setColor(Color.TRANSPARENT);
+ mBorderPaint.setStyle(Style.STROKE);
+ mBorderPaint.setStrokeWidth(mBorderWidth);
+ mBorderPaint.setAntiAlias(true);
+
+ mScrimColor = Color.TRANSPARENT;
+ }
+
+ /**
+ * Set the border stroke width of this drawable.
+ */
+ public void setBorderWidth(final float borderWidth) {
+ final boolean changed = mBorderPaint.getStrokeWidth() != borderWidth;
+ mBorderPaint.setStrokeWidth(borderWidth);
+ mBorderWidth = borderWidth;
+
+ if (changed) {
+ invalidateSelf();
+ }
+ }
+
+ /**
+ * Set the border stroke color of this drawable. Set to {@link Color#TRANSPARENT} to disable.
+ */
+ public void setBorderColor(final int color) {
+ final boolean changed = mBorderPaint.getColor() != color;
+ mBorderPaint.setColor(color);
+
+ if (changed) {
+ invalidateSelf();
+ }
+ }
+
+ /** Set the corner styles for all four corners */
+ public void setCornerStyles(int topLeft, int topRight, int bottomRight, int bottomLeft) {
+ boolean changed = mTopLeftCornerStyle != topLeft
+ || mTopRightCornerStyle != topRight
+ || mBottomRightCornerStyle != bottomRight
+ || mBottomLeftCornerStyle != bottomLeft;
+
+ mTopLeftCornerStyle = topLeft;
+ mTopRightCornerStyle = topRight;
+ mBottomRightCornerStyle = bottomRight;
+ mBottomLeftCornerStyle = bottomLeft;
+
+ if (changed) {
+ recalculatePath();
+ }
+ }
+
+ /**
+ * Set the flap color for all corners that have style {@link #CORNER_STYLE_SHARP}.
+ *
+ * Use {@link android.graphics.Color#TRANSPARENT} to disable flap colors.
+ */
+ public void setFlapColor(int flapColor) {
+ boolean changed = mFlapPaint.getColor() != flapColor;
+ mFlapPaint.setColor(flapColor);
+
+ if (changed) {
+ invalidateSelf();
+ }
+ }
+
+ /**
+ * Get the color of the scrim that is drawn over the contents, but under the flaps and borders.
+ */
+ public int getScrimColor() {
+ return mScrimColor;
+ }
+
+ /**
+ * 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.
+ */
+ public void setScrimColor(int color) {
+ boolean changed = mScrimColor != color;
+ mScrimColor = color;
+
+ if (changed) {
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+
+ recalculatePath();
+ }
+
+ /**
+ * Override draw(android.graphics.Canvas) instead of
+ * {@link #onDraw(android.graphics.Canvas)} to clip all the drawable layers.
+ */
+ @Override
+ public void draw(Canvas canvas) {
+ final Rect bounds = getBounds();
+ if (bounds.isEmpty()) {
+ return;
+ }
+
+ // Clip to path.
+ canvas.save();
+ canvas.clipPath(mClipPath);
+
+ // Draw parent within path.
+ super.draw(canvas);
+
+ // Draw scrim on top of parent.
+ canvas.drawColor(mScrimColor);
+
+ // Draw flap.
+ 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);
+ }
+
+ canvas.restore();
+
+ // Draw border around path.
+ canvas.drawPath(mClipPath, mBorderPaint);
+ }
+
+ protected Path getClipPath() {
+ return mClipPath;
+ }
+
+ 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();
+ }
+}