/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.drawee.drawable;
import java.util.Arrays;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import com.facebook.common.internal.Preconditions;
import com.facebook.common.internal.VisibleForTesting;
public class RoundedColorDrawable extends Drawable {
@VisibleForTesting final float[] mRadii = new float[8];
@VisibleForTesting final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@VisibleForTesting boolean mIsCircle = false;
@VisibleForTesting float mBorderWidth = 0;
@VisibleForTesting int mBorderColor = Color.TRANSPARENT;
@VisibleForTesting final Path mPath = new Path();
private int mColor = Color.TRANSPARENT;
private final RectF mTempRect = new RectF();
private int mAlpha = 255;
/**
* Creates a RoundedColorDrawable.
*
* @param color of the drawable
*/
public RoundedColorDrawable(int color) {
setColor(color);
}
/**
* Creates a new instance of RoundedColorDrawable from the given ColorDrawable.
* @param colorDrawable color drawable to extract the color from
* @return a new RoundedColorDrawable
*/
public static RoundedColorDrawable fromColorDrawable(ColorDrawable colorDrawable) {
return new RoundedColorDrawable(colorDrawable.getColor());
}
/**
* Creates a new instance of RoundedColorDrawable.
*
* @param radii Each corner receive two radius values [X, Y]. The corners are ordered
* top-left, top-right, bottom-right, bottom-left.
* @param color of the drawable
*/
public RoundedColorDrawable(float[] radii, int color) {
this(color);
setRadii(radii);
}
/**
* Creates a new instance of RoundedColorDrawable.
*
* @param radius of the corners in pixels
* @param color of the drawable
*/
public RoundedColorDrawable(float radius, int color) {
this(color);
setRadius(radius);
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
updatePath();
}
@Override
public void draw(Canvas canvas) {
mPaint.setColor(DrawableUtils.multiplyColorAlpha(mColor, mAlpha));
mPaint.setStyle(Paint.Style.FILL);
canvas.drawPath(mPath, mPaint);
if (mBorderWidth != 0) {
mPaint.setColor(DrawableUtils.multiplyColorAlpha(mBorderColor, mAlpha));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mBorderWidth);
canvas.drawPath(mPath, mPaint);
}
}
/**
* Sets whether to round as circle.
*
* @param isCircle whether or not to round as circle
*/
public void setCircle(boolean isCircle) {
mIsCircle = isCircle;
updatePath();
invalidateSelf();
}
/**
* Sets the rounding radii.
*
* @param radii Each corner receive two radius values [X, Y]. The corners are ordered
* top-left, top-right, bottom-right, bottom-left
*/
public void setRadii(float[] radii) {
if (radii == null) {
Arrays.fill(mRadii, 0);
} else {
Preconditions.checkArgument(radii.length == 8, "radii should have exactly 8 values");
System.arraycopy(radii, 0, mRadii, 0, 8);
}
updatePath();
invalidateSelf();
}
/**
* Sets the rounding radius.
*
* @param radius
*/
public void setRadius(float radius) {
Preconditions.checkArgument(radius >= 0, "radius should be non negative");
Arrays.fill(mRadii, radius);
updatePath();
invalidateSelf();
}
/**
* Sets the color.
* @param color
*/
public void setColor(int color) {
if (mColor != color) {
mColor = color;
invalidateSelf();
}
}
/**
* Gets the color.
* @return color
*/
public int getColor() {
return mColor;
}
/**
* Sets the border
* @param color of the border
* @param width of the border
*/
public void setBorder(int color, float width) {
if (mBorderColor != color) {
mBorderColor = color;
invalidateSelf();
}
if (mBorderWidth != width) {
mBorderWidth = width;
updatePath();
invalidateSelf();
}
}
/**
* Sets the drawable's alpha value.
*
* @param alpha The alpha value to set, between 0 and 255.
*/
@Override
public void setAlpha(int alpha) {
if (alpha != mAlpha) {
mAlpha = alpha;
invalidateSelf();
}
}
/**
* Returns the drawable's alpha value.
*
* @return A value between 0 and 255.
*/
@Override
public int getAlpha() {
return mAlpha;
}
/**
* Setting a color filter on a ColorDrawable has no effect. This has been inspired by Android
* ColorDrawable.
*
* @param colorFilter Ignore.
*/
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
/**
* Returns the opacity of the final color which would be used for drawing. This has been
* inspired by Android ColorDrawable.
*
* @return the opacity
*/
@Override
public int getOpacity() {
return DrawableUtils.getOpacityFromColor(DrawableUtils.multiplyColorAlpha(mColor, mAlpha));
}
private void updatePath() {
mPath.reset();
mTempRect.set(getBounds());
mTempRect.inset(mBorderWidth/2, mBorderWidth/2);
if (mIsCircle) {
float radius = Math.min(mTempRect.width(), mTempRect.height()) / 2;
mPath.addCircle(mTempRect.centerX(), mTempRect.centerY(), radius, Path.Direction.CW);
} else {
mPath.addRoundRect(mTempRect, mRadii, Path.Direction.CW);
}
mTempRect.inset(-mBorderWidth/2, -mBorderWidth/2);
}
}