319 lines
12 KiB
Java
319 lines
12 KiB
Java
|
package androidx.cardview.widget;
|
||
|
|
||
|
import android.content.res.ColorStateList;
|
||
|
import android.content.res.Resources;
|
||
|
import android.graphics.Canvas;
|
||
|
import android.graphics.ColorFilter;
|
||
|
import android.graphics.LinearGradient;
|
||
|
import android.graphics.Paint;
|
||
|
import android.graphics.Path;
|
||
|
import android.graphics.RadialGradient;
|
||
|
import android.graphics.Rect;
|
||
|
import android.graphics.RectF;
|
||
|
import android.graphics.Shader;
|
||
|
import android.graphics.drawable.Drawable;
|
||
|
import androidx.annotation.Nullable;
|
||
|
import androidx.cardview.R;
|
||
|
public class RoundRectDrawableWithShadow extends Drawable {
|
||
|
private static final double COS_45 = Math.cos(Math.toRadians(45.0d));
|
||
|
private static final float SHADOW_MULTIPLIER = 1.5f;
|
||
|
public static RoundRectHelper sRoundRectHelper;
|
||
|
private boolean mAddPaddingForCorners = true;
|
||
|
private ColorStateList mBackground;
|
||
|
private final RectF mCardBounds;
|
||
|
private float mCornerRadius;
|
||
|
private Paint mCornerShadowPaint;
|
||
|
private Path mCornerShadowPath;
|
||
|
private boolean mDirty = true;
|
||
|
private Paint mEdgeShadowPaint;
|
||
|
private final int mInsetShadow;
|
||
|
private Paint mPaint;
|
||
|
private boolean mPrintedShadowClipWarning = false;
|
||
|
private float mRawMaxShadowSize;
|
||
|
private float mRawShadowSize;
|
||
|
private final int mShadowEndColor;
|
||
|
private float mShadowSize;
|
||
|
private final int mShadowStartColor;
|
||
|
|
||
|
public interface RoundRectHelper {
|
||
|
void drawRoundRect(Canvas canvas, RectF rectF, float f, Paint paint);
|
||
|
}
|
||
|
|
||
|
public RoundRectDrawableWithShadow(Resources resources, ColorStateList colorStateList, float f, float f2, float f3) {
|
||
|
this.mShadowStartColor = resources.getColor(R.color.cardview_shadow_start_color);
|
||
|
this.mShadowEndColor = resources.getColor(R.color.cardview_shadow_end_color);
|
||
|
this.mInsetShadow = resources.getDimensionPixelSize(R.dimen.cardview_compat_inset_shadow);
|
||
|
this.mPaint = new Paint(5);
|
||
|
setBackground(colorStateList);
|
||
|
Paint paint = new Paint(5);
|
||
|
this.mCornerShadowPaint = paint;
|
||
|
paint.setStyle(Paint.Style.FILL);
|
||
|
this.mCornerRadius = (float) ((int) (f + 0.5f));
|
||
|
this.mCardBounds = new RectF();
|
||
|
Paint paint2 = new Paint(this.mCornerShadowPaint);
|
||
|
this.mEdgeShadowPaint = paint2;
|
||
|
paint2.setAntiAlias(false);
|
||
|
setShadowSize(f2, f3);
|
||
|
}
|
||
|
|
||
|
private void buildComponents(Rect rect) {
|
||
|
float f = this.mRawMaxShadowSize;
|
||
|
float f2 = 1.5f * f;
|
||
|
this.mCardBounds.set(((float) rect.left) + f, ((float) rect.top) + f2, ((float) rect.right) - f, ((float) rect.bottom) - f2);
|
||
|
buildShadowCorners();
|
||
|
}
|
||
|
|
||
|
private void buildShadowCorners() {
|
||
|
float f = this.mCornerRadius;
|
||
|
RectF rectF = new RectF(-f, -f, f, f);
|
||
|
RectF rectF2 = new RectF(rectF);
|
||
|
float f2 = this.mShadowSize;
|
||
|
rectF2.inset(-f2, -f2);
|
||
|
Path path = this.mCornerShadowPath;
|
||
|
if (path == null) {
|
||
|
this.mCornerShadowPath = new Path();
|
||
|
} else {
|
||
|
path.reset();
|
||
|
}
|
||
|
this.mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD);
|
||
|
this.mCornerShadowPath.moveTo(-this.mCornerRadius, 0.0f);
|
||
|
this.mCornerShadowPath.rLineTo(-this.mShadowSize, 0.0f);
|
||
|
this.mCornerShadowPath.arcTo(rectF2, 180.0f, 90.0f, false);
|
||
|
this.mCornerShadowPath.arcTo(rectF, 270.0f, -90.0f, false);
|
||
|
this.mCornerShadowPath.close();
|
||
|
float f3 = this.mCornerRadius;
|
||
|
float f4 = f3 / (this.mShadowSize + f3);
|
||
|
Paint paint = this.mCornerShadowPaint;
|
||
|
float f5 = this.mCornerRadius + this.mShadowSize;
|
||
|
int i = this.mShadowStartColor;
|
||
|
paint.setShader(new RadialGradient(0.0f, 0.0f, f5, new int[]{i, i, this.mShadowEndColor}, new float[]{0.0f, f4, 1.0f}, Shader.TileMode.CLAMP));
|
||
|
Paint paint2 = this.mEdgeShadowPaint;
|
||
|
float f6 = this.mCornerRadius;
|
||
|
float f7 = this.mShadowSize;
|
||
|
int i2 = this.mShadowStartColor;
|
||
|
paint2.setShader(new LinearGradient(0.0f, (-f6) + f7, 0.0f, (-f6) - f7, new int[]{i2, i2, this.mShadowEndColor}, new float[]{0.0f, 0.5f, 1.0f}, Shader.TileMode.CLAMP));
|
||
|
this.mEdgeShadowPaint.setAntiAlias(false);
|
||
|
}
|
||
|
|
||
|
public static float calculateHorizontalPadding(float f, float f2, boolean z2) {
|
||
|
if (!z2) {
|
||
|
return f;
|
||
|
}
|
||
|
return (float) (((1.0d - COS_45) * ((double) f2)) + ((double) f));
|
||
|
}
|
||
|
|
||
|
public static float calculateVerticalPadding(float f, float f2, boolean z2) {
|
||
|
if (!z2) {
|
||
|
return f * 1.5f;
|
||
|
}
|
||
|
return (float) (((1.0d - COS_45) * ((double) f2)) + ((double) (f * 1.5f)));
|
||
|
}
|
||
|
|
||
|
private void drawShadow(Canvas canvas) {
|
||
|
float f = this.mCornerRadius;
|
||
|
float f2 = (-f) - this.mShadowSize;
|
||
|
float f3 = (this.mRawShadowSize / 2.0f) + f + ((float) this.mInsetShadow);
|
||
|
float f4 = f3 * 2.0f;
|
||
|
boolean z2 = this.mCardBounds.width() - f4 > 0.0f;
|
||
|
boolean z3 = this.mCardBounds.height() - f4 > 0.0f;
|
||
|
int save = canvas.save();
|
||
|
RectF rectF = this.mCardBounds;
|
||
|
canvas.translate(rectF.left + f3, rectF.top + f3);
|
||
|
canvas.drawPath(this.mCornerShadowPath, this.mCornerShadowPaint);
|
||
|
if (z2) {
|
||
|
canvas.drawRect(0.0f, f2, this.mCardBounds.width() - f4, -this.mCornerRadius, this.mEdgeShadowPaint);
|
||
|
}
|
||
|
canvas.restoreToCount(save);
|
||
|
int save2 = canvas.save();
|
||
|
RectF rectF2 = this.mCardBounds;
|
||
|
canvas.translate(rectF2.right - f3, rectF2.bottom - f3);
|
||
|
canvas.rotate(180.0f);
|
||
|
canvas.drawPath(this.mCornerShadowPath, this.mCornerShadowPaint);
|
||
|
if (z2) {
|
||
|
canvas.drawRect(0.0f, f2, this.mCardBounds.width() - f4, (-this.mCornerRadius) + this.mShadowSize, this.mEdgeShadowPaint);
|
||
|
}
|
||
|
canvas.restoreToCount(save2);
|
||
|
int save3 = canvas.save();
|
||
|
RectF rectF3 = this.mCardBounds;
|
||
|
canvas.translate(rectF3.left + f3, rectF3.bottom - f3);
|
||
|
canvas.rotate(270.0f);
|
||
|
canvas.drawPath(this.mCornerShadowPath, this.mCornerShadowPaint);
|
||
|
if (z3) {
|
||
|
canvas.drawRect(0.0f, f2, this.mCardBounds.height() - f4, -this.mCornerRadius, this.mEdgeShadowPaint);
|
||
|
}
|
||
|
canvas.restoreToCount(save3);
|
||
|
int save4 = canvas.save();
|
||
|
RectF rectF4 = this.mCardBounds;
|
||
|
canvas.translate(rectF4.right - f3, rectF4.top + f3);
|
||
|
canvas.rotate(90.0f);
|
||
|
canvas.drawPath(this.mCornerShadowPath, this.mCornerShadowPaint);
|
||
|
if (z3) {
|
||
|
canvas.drawRect(0.0f, f2, this.mCardBounds.height() - f4, -this.mCornerRadius, this.mEdgeShadowPaint);
|
||
|
}
|
||
|
canvas.restoreToCount(save4);
|
||
|
}
|
||
|
|
||
|
private void setBackground(ColorStateList colorStateList) {
|
||
|
if (colorStateList == null) {
|
||
|
colorStateList = ColorStateList.valueOf(0);
|
||
|
}
|
||
|
this.mBackground = colorStateList;
|
||
|
this.mPaint.setColor(colorStateList.getColorForState(getState(), this.mBackground.getDefaultColor()));
|
||
|
}
|
||
|
|
||
|
private void setShadowSize(float f, float f2) {
|
||
|
if (f < 0.0f) {
|
||
|
throw new IllegalArgumentException("Invalid shadow size " + f + ". Must be >= 0");
|
||
|
} else if (f2 >= 0.0f) {
|
||
|
float even = (float) toEven(f);
|
||
|
float even2 = (float) toEven(f2);
|
||
|
if (even > even2) {
|
||
|
if (!this.mPrintedShadowClipWarning) {
|
||
|
this.mPrintedShadowClipWarning = true;
|
||
|
}
|
||
|
even = even2;
|
||
|
}
|
||
|
if (this.mRawShadowSize != even || this.mRawMaxShadowSize != even2) {
|
||
|
this.mRawShadowSize = even;
|
||
|
this.mRawMaxShadowSize = even2;
|
||
|
this.mShadowSize = (float) ((int) ((even * 1.5f) + ((float) this.mInsetShadow) + 0.5f));
|
||
|
this.mDirty = true;
|
||
|
invalidateSelf();
|
||
|
}
|
||
|
} else {
|
||
|
throw new IllegalArgumentException("Invalid max shadow size " + f2 + ". Must be >= 0");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private int toEven(float f) {
|
||
|
int i = (int) (f + 0.5f);
|
||
|
return i % 2 == 1 ? i - 1 : i;
|
||
|
}
|
||
|
|
||
|
@Override // android.graphics.drawable.Drawable
|
||
|
public void draw(Canvas canvas) {
|
||
|
if (this.mDirty) {
|
||
|
buildComponents(getBounds());
|
||
|
this.mDirty = false;
|
||
|
}
|
||
|
canvas.translate(0.0f, this.mRawShadowSize / 2.0f);
|
||
|
drawShadow(canvas);
|
||
|
canvas.translate(0.0f, (-this.mRawShadowSize) / 2.0f);
|
||
|
sRoundRectHelper.drawRoundRect(canvas, this.mCardBounds, this.mCornerRadius, this.mPaint);
|
||
|
}
|
||
|
|
||
|
public ColorStateList getColor() {
|
||
|
return this.mBackground;
|
||
|
}
|
||
|
|
||
|
public float getCornerRadius() {
|
||
|
return this.mCornerRadius;
|
||
|
}
|
||
|
|
||
|
public void getMaxShadowAndCornerPadding(Rect rect) {
|
||
|
getPadding(rect);
|
||
|
}
|
||
|
|
||
|
public float getMaxShadowSize() {
|
||
|
return this.mRawMaxShadowSize;
|
||
|
}
|
||
|
|
||
|
public float getMinHeight() {
|
||
|
float f = this.mRawMaxShadowSize;
|
||
|
float f2 = (f * 1.5f) / 2.0f;
|
||
|
return (((this.mRawMaxShadowSize * 1.5f) + ((float) this.mInsetShadow)) * 2.0f) + (Math.max(f, f2 + this.mCornerRadius + ((float) this.mInsetShadow)) * 2.0f);
|
||
|
}
|
||
|
|
||
|
public float getMinWidth() {
|
||
|
float f = this.mRawMaxShadowSize;
|
||
|
float f2 = f / 2.0f;
|
||
|
return ((this.mRawMaxShadowSize + ((float) this.mInsetShadow)) * 2.0f) + (Math.max(f, f2 + this.mCornerRadius + ((float) this.mInsetShadow)) * 2.0f);
|
||
|
}
|
||
|
|
||
|
@Override // android.graphics.drawable.Drawable
|
||
|
public int getOpacity() {
|
||
|
return -3;
|
||
|
}
|
||
|
|
||
|
@Override // android.graphics.drawable.Drawable
|
||
|
public boolean getPadding(Rect rect) {
|
||
|
int ceil = (int) Math.ceil((double) calculateVerticalPadding(this.mRawMaxShadowSize, this.mCornerRadius, this.mAddPaddingForCorners));
|
||
|
int ceil2 = (int) Math.ceil((double) calculateHorizontalPadding(this.mRawMaxShadowSize, this.mCornerRadius, this.mAddPaddingForCorners));
|
||
|
rect.set(ceil2, ceil, ceil2, ceil);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public float getShadowSize() {
|
||
|
return this.mRawShadowSize;
|
||
|
}
|
||
|
|
||
|
@Override // android.graphics.drawable.Drawable
|
||
|
public boolean isStateful() {
|
||
|
ColorStateList colorStateList = this.mBackground;
|
||
|
return (colorStateList != null && colorStateList.isStateful()) || super.isStateful();
|
||
|
}
|
||
|
|
||
|
@Override // android.graphics.drawable.Drawable
|
||
|
public void onBoundsChange(Rect rect) {
|
||
|
super.onBoundsChange(rect);
|
||
|
this.mDirty = true;
|
||
|
}
|
||
|
|
||
|
@Override // android.graphics.drawable.Drawable
|
||
|
public boolean onStateChange(int[] iArr) {
|
||
|
ColorStateList colorStateList = this.mBackground;
|
||
|
int colorForState = colorStateList.getColorForState(iArr, colorStateList.getDefaultColor());
|
||
|
if (this.mPaint.getColor() == colorForState) {
|
||
|
return false;
|
||
|
}
|
||
|
this.mPaint.setColor(colorForState);
|
||
|
this.mDirty = true;
|
||
|
invalidateSelf();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public void setAddPaddingForCorners(boolean z2) {
|
||
|
this.mAddPaddingForCorners = z2;
|
||
|
invalidateSelf();
|
||
|
}
|
||
|
|
||
|
@Override // android.graphics.drawable.Drawable
|
||
|
public void setAlpha(int i) {
|
||
|
this.mPaint.setAlpha(i);
|
||
|
this.mCornerShadowPaint.setAlpha(i);
|
||
|
this.mEdgeShadowPaint.setAlpha(i);
|
||
|
}
|
||
|
|
||
|
public void setColor(@Nullable ColorStateList colorStateList) {
|
||
|
setBackground(colorStateList);
|
||
|
invalidateSelf();
|
||
|
}
|
||
|
|
||
|
@Override // android.graphics.drawable.Drawable
|
||
|
public void setColorFilter(ColorFilter colorFilter) {
|
||
|
this.mPaint.setColorFilter(colorFilter);
|
||
|
}
|
||
|
|
||
|
public void setCornerRadius(float f) {
|
||
|
if (f >= 0.0f) {
|
||
|
float f2 = (float) ((int) (f + 0.5f));
|
||
|
if (this.mCornerRadius != f2) {
|
||
|
this.mCornerRadius = f2;
|
||
|
this.mDirty = true;
|
||
|
invalidateSelf();
|
||
|
return;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
throw new IllegalArgumentException("Invalid radius " + f + ". Must be >= 0");
|
||
|
}
|
||
|
|
||
|
public void setMaxShadowSize(float f) {
|
||
|
setShadowSize(this.mRawShadowSize, f);
|
||
|
}
|
||
|
|
||
|
public void setShadowSize(float f) {
|
||
|
setShadowSize(f, this.mRawMaxShadowSize);
|
||
|
}
|
||
|
}
|