
1.定义全部圆角的通用接口
public interface IRadiusLayout {
int SOLID_TYPE_SOLID = 0;
void setBackgroundColor(ColorStateList bgColorStateList);
void setSolidDashPathEffect(DashPathEffect dashPathEffect);
void setSolidColor(int color);
void setSolidColor(ColorStateList solidColorStateList);
void setRadius(int radius);
void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius);
void setLeftTopRadius(int leftTopRadius);
void setRightTopRadius(int rightTopRadius);
void setRightBottomRadius(int rightBottomRadius);
void setLeftBottomRadius(int leftBottomRadius);
void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors);
void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation);
void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors);
void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation);
2.定义渐变工具ShaderUtils
public class ShaderUtils {
public static final int COLOR_VALUE_NONE = -0xFFFFFFFF;
public static final int SHADER_TYPE_LINEAR = 10;
public static final int SHADER_TYPE_RADIAL = 11;
public static final int SHADER_TYPE_SWEEP = 12;
public static final int SHADER_TYPE_NONE = -1;
public static final int LINEAR_ORIENTATION_TOP_TO_BOTTOM = 110;
public static final int LINEAR_ORIENTATION_BOTTOM_TO_TOP = 111;
public static final int LINEAR_ORIENTATION_LEFT_TO_RIGHT = 220;
public static final int LINEAR_ORIENTATION_RIGHT_TO_LEFT = 221;
public static final int LINEAR_ORIENTATION_LEFT_TOP_TO_RIGHT_BOTTOM = 330;
public static final int LINEAR_ORIENTATION_RIGHT_BOTTOM_TO_LEFT_TOP = 331;
public static final int LINEAR_ORIENTATION_RIGHT_TOP_TO_LEFT_BOTTOM = 440;
public static final int LINEAR_ORIENTATION_LEFT_BOTTOM_TO_RIGHT_TOP = 441;
@IntDef(value = {SHADER_TYPE_LINEAR, SHADER_TYPE_RADIAL, SHADER_TYPE_SWEEP})
public @interface ShaderType {
@IntDef(value = {LINEAR_ORIENTATION_TOP_TO_BOTTOM, LINEAR_ORIENTATION_BOTTOM_TO_TOP,
LINEAR_ORIENTATION_LEFT_TO_RIGHT, LINEAR_ORIENTATION_RIGHT_TO_LEFT,
LINEAR_ORIENTATION_LEFT_TOP_TO_RIGHT_BOTTOM, LINEAR_ORIENTATION_RIGHT_BOTTOM_TO_LEFT_TOP,
LINEAR_ORIENTATION_RIGHT_TOP_TO_LEFT_BOTTOM, LINEAR_ORIENTATION_LEFT_BOTTOM_TO_RIGHT_TOP})
public @interface LinearOrientation {
public static Shader createShader(@ShaderType int shaderType, int width, int height, int[] colors, @LinearOrientation int orientation) {
if (shaderType == SHADER_TYPE_LINEAR) {
return createLinearGradient(width, height, colors, orientation);
} else if (shaderType == SHADER_TYPE_RADIAL) {
return createRadialGradient(width, height, colors);
} else if (shaderType == SHADER_TYPE_SWEEP) {
return createSweepGradient(width, height, colors);
return createLinearGradient(width, height, colors, orientation);
public static LinearGradient createLinearGradient(int width, int height, int[] colors, @LinearOrientation int orientation) {
LinearGradient linearGradient;
int halfWidth = width / 2;
int halfHeight = height / 2;
if (LINEAR_ORIENTATION_TOP_TO_BOTTOM == orientation) {
linearGradient = new LinearGradient(halfWidth, 0, halfWidth, height, colors, null, Shader.TileMode.CLAMP);
} else if (LINEAR_ORIENTATION_BOTTOM_TO_TOP == orientation) {
linearGradient = new LinearGradient(halfWidth, height, halfWidth, 0, colors, null, Shader.TileMode.CLAMP);
} else if (LINEAR_ORIENTATION_LEFT_TO_RIGHT == orientation) {
linearGradient = new LinearGradient(0, halfHeight, width, halfHeight, colors, null, Shader.TileMode.CLAMP);
} else if (LINEAR_ORIENTATION_RIGHT_TO_LEFT == orientation) {
linearGradient = new LinearGradient(width, halfHeight, 0, halfHeight, colors, null, Shader.TileMode.CLAMP);
} else if (LINEAR_ORIENTATION_LEFT_TOP_TO_RIGHT_BOTTOM == orientation) {
linearGradient = new LinearGradient(0, 0, width, height, colors, null, Shader.TileMode.CLAMP);
} else if (LINEAR_ORIENTATION_RIGHT_BOTTOM_TO_LEFT_TOP == orientation) {
linearGradient = new LinearGradient(width, height, 0, 0, colors, null, Shader.TileMode.CLAMP);
} else if (LINEAR_ORIENTATION_RIGHT_TOP_TO_LEFT_BOTTOM == orientation) {
linearGradient = new LinearGradient(width, 0, 0, height, colors, null, Shader.TileMode.CLAMP);
} else if (LINEAR_ORIENTATION_LEFT_BOTTOM_TO_RIGHT_TOP == orientation) {
linearGradient = new LinearGradient(0, height, width, 0, colors, null, Shader.TileMode.CLAMP);
linearGradient = new LinearGradient(halfWidth, 0, halfWidth, height, colors, null, Shader.TileMode.CLAMP);
public static RadialGradient createRadialGradient(int width, int height, int[] colors) {
int halfWidth = width / 2;
int halfHeight = height / 2;
return new RadialGradient(halfWidth, halfHeight, Math.min(halfWidth, halfHeight), colors, null, Shader.TileMode.CLAMP);
public static SweepGradient createSweepGradient(int width, int height, int[] colors) {
int halfWidth = width / 2;
int halfHeight = height / 2;
return new SweepGradient(halfWidth, halfHeight, colors, null);
public static int[] createColorsArray(int startColor, int middleColor, int middleColor2, int middleColor3, int endColor) {
List colors = new ArrayList<>();
if (startColor != COLOR_VALUE_NONE) {
if (middleColor != COLOR_VALUE_NONE) {
if (middleColor2 != COLOR_VALUE_NONE) {
colors.add(middleColor2);
if (middleColor3 != COLOR_VALUE_NONE) {
colors.add(middleColor3);
if (endColor != COLOR_VALUE_NONE) {
int[] shaderColors = new int[colors.size()];
for (int i = 0; i < colors.size(); i++) {
shaderColors[i] = colors.get(i);
public static int[] createColorsArray(int startColor, int middleColor, int endColor) {
List colors = new ArrayList<>();
if (startColor != COLOR_VALUE_NONE) {
if (middleColor != COLOR_VALUE_NONE) {
if (endColor != COLOR_VALUE_NONE) {
int[] shaderColors = new int[colors.size()];
for (int i = 0; i < colors.size(); i++) {
shaderColors[i] = colors.get(i);
3.圆角工具RadiusUtils
public class RadiusUtils {
public static final int TYPE_NONE = 0x0000;
public static final int TYPE_RADIUS = 0x0001;
public static final int TYPE_CIRCLE = 0x0002;
public static final int TYPE_OVAL_LEFT = 0x0004;
public static final int TYPE_OVAL_TOP = 0x0008;
public static final int TYPE_OVAL_RIGHT = 0x0010;
public static final int TYPE_OVAL_BOTTOM = 0x0020;
public static Path calculateBgPath(int leftTopRadius, int rightTopRadius,
int leftBottomRadius, int rightBottomRadius,
return calculateBgPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height, true);
public static Path calculateBgPath(int leftTopRadius, int rightTopRadius,
int leftBottomRadius, int rightBottomRadius,
int width, int height, boolean isGetType) {
leftTopRadius = Math.max(leftTopRadius, 0);
rightTopRadius = Math.max(rightTopRadius, 0);
leftBottomRadius = Math.max(leftBottomRadius, 0);
rightBottomRadius = Math.max(rightBottomRadius, 0);
int type = getType(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height);
return calculateRectBgPath(width, height);
return calculateRadiusBgPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height);
if (type == TYPE_CIRCLE) {
Path resultPath = new Path();
RectF rectF = new RectF();
rectF.set(0, 0, width, height);
resultPath.addCircle(rectF.centerX(), rectF.centerY(), Math.min(rectF.width(), rectF.height()) / 2f, Path.Direction.CW);
Path resultPath = new Path();
if (((type & TYPE_OVAL_LEFT) != 0) && (type & TYPE_OVAL_RIGHT) != 0) {
RectF arcRectF = new RectF();
arcRectF.set(0, 0, height, height);
resultPath.addArc(arcRectF, 90, 180);
resultPath.lineTo(width - height / 2f, 0);
RectF rightRectF = new RectF();
rightRectF.set(width - height, 0, width, height);
resultPath.addArc(rightRectF, -90, 180);
resultPath.lineTo(height / 2f, height);
} else if (((type & TYPE_OVAL_TOP) != 0) && (type & TYPE_OVAL_BOTTOM) != 0) {
RectF arcRectF = new RectF();
arcRectF.set(0, 0, width, width);
resultPath.addArc(arcRectF, 180, 180);
resultPath.lineTo(width, height - width / 2f);
RectF rightRectF = new RectF();
rightRectF.set(0, height - width, width, height);
resultPath.addArc(rightRectF, 0, 180);
resultPath.lineTo(0, width / 2f);
} else if ((type & TYPE_OVAL_LEFT) != 0) {
RectF arcRectF = new RectF();
arcRectF.set(0, 0, height, height);
resultPath.addArc(arcRectF, 90, 180);
resultPath.lineTo(width - rightTopRadius, 0);
resultPath.quadTo(width, 0, width, rightTopRadius);
resultPath.lineTo(width, height - rightBottomRadius);
resultPath.quadTo(width, height, width - rightBottomRadius, height);
resultPath.lineTo(height / 2f, height);
} else if ((type & TYPE_OVAL_RIGHT) != 0) {
resultPath.moveTo(leftTopRadius, 0);
resultPath.lineTo(width - height / 2f, 0);
RectF rightRectF = new RectF();
rightRectF.set(width - height, 0, width, height);
resultPath.addArc(rightRectF, -90, 180);
resultPath.lineTo(leftBottomRadius, height);
resultPath.quadTo(0, height, 0, height - leftBottomRadius);
resultPath.lineTo(0, leftTopRadius);
resultPath.quadTo(0, 0, leftTopRadius, 0);
} else if ((type & TYPE_OVAL_TOP) != 0) {
RectF arcRectF = new RectF();
arcRectF.set(0, 0, width, width);
resultPath.addArc(arcRectF, 180, 180);
resultPath.lineTo(width, height - rightBottomRadius);
resultPath.quadTo(width, height, width - rightBottomRadius, height);
resultPath.lineTo(leftBottomRadius, height);
resultPath.quadTo(0, height, 0, height - leftBottomRadius);
resultPath.lineTo(0, width / 2f);
} else if ((type & TYPE_OVAL_BOTTOM) != 0) {
resultPath.moveTo(leftTopRadius, 0);
resultPath.lineTo(width - rightTopRadius, 0);
resultPath.quadTo(width, 0, width, rightTopRadius);
resultPath.lineTo(width, height - width / 2f);
RectF rightRectF = new RectF();
rightRectF.set(0, height - width, width, height);
resultPath.addArc(rightRectF, 0, 180);
resultPath.lineTo(0, leftTopRadius);
resultPath.quadTo(0, 0, leftTopRadius, 0);
return calculateRadiusBgPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height);
return calculateRadiusBgPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height);
private static Path calculateRadiusBgPath(int leftTopRadius, int rightTopRadius, int leftBottomRadius,
int rightBottomRadius, int width, int height) {
float leftTopRadiusLeft, leftTopRadiusTop;
float leftBottomRadiusLeft, leftBottomRadiusBottom;
float rightTopRadiusRight, rightTopRadiusTop;
float rightBottomRadiusRight, rightBottomRadiusBottom;
int[] sideTop = calculateRadiusLength(leftTopRadius, rightTopRadius, width);
int[] sideBottom = calculateRadiusLength(leftBottomRadius, rightBottomRadius, width);
int[] sideLeft = calculateRadiusLength(leftTopRadius, leftBottomRadius, height);
int[] sideRight = calculateRadiusLength(rightTopRadius, rightBottomRadius, height);
leftTopRadiusTop = sideTop[0];
rightTopRadiusTop = sideTop[1];
leftBottomRadiusBottom = sideBottom[0];
rightBottomRadiusBottom = sideBottom[1];
leftTopRadiusLeft = sideLeft[0];
leftBottomRadiusLeft = sideLeft[1];
rightTopRadiusRight = sideRight[0];
rightBottomRadiusRight = sideRight[1];
Path resultPath = new Path();
resultPath.moveTo(leftTopRadiusTop, 0);
resultPath.lineTo(width - rightTopRadiusTop, 0);
resultPath.quadTo(width, 0, width, rightTopRadiusRight);
resultPath.lineTo(width, height - rightBottomRadiusRight);
resultPath.quadTo(width, height, width - rightBottomRadiusBottom, height);
resultPath.lineTo(leftBottomRadiusBottom, height);
resultPath.quadTo(0, height, 0, height - leftBottomRadiusLeft);
resultPath.lineTo(0, leftTopRadiusLeft);
resultPath.quadTo(0, 0, leftTopRadiusTop, 0);
private static Path calculateRectBgPath(int width, int height) {
Path result = new Path();
result.lineTo(width, height);
result.lineTo(0, height);
public static Path[] calculateSocketPath(int leftTopRadius, int rightTopRadius,
int leftBottomRadius, int rightBottomRadius,
int width, int height, int solidWidth) {
leftTopRadius = Math.max(leftTopRadius, 0);
rightTopRadius = Math.max(rightTopRadius, 0);
leftBottomRadius = Math.max(leftBottomRadius, 0);
rightBottomRadius = Math.max(rightBottomRadius, 0);
int type = getType(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height);
return new Path[]{calculateRectSocketPath(width, height, solidWidth)};
return calculateRadiusSocketPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height, solidWidth);
if (type == TYPE_CIRCLE) {
Path[] result = new Path[1];
Path resultPath = new Path();
RectF rectF = new RectF();
rectF.set(0, 0, width, height);
float newWidth = solidWidth / 2.0f;
rectF.inset(newWidth, newWidth);
resultPath.addCircle(rectF.centerX(), rectF.centerY(), Math.min(rectF.width(), rectF.height()) / 2f, Path.Direction.CW);
Path[] result = new Path[1];
Path resultPath = new Path();
float newWidth = solidWidth / 2.0f;
if (((type & TYPE_OVAL_LEFT) != 0) && (type & TYPE_OVAL_RIGHT) != 0) {
RectF leftRectF = new RectF();
leftRectF.set(newWidth, newWidth, height, height - newWidth);
resultPath.addArc(leftRectF, 90, 180);
resultPath.lineTo(width - height / 2f, newWidth);
RectF rightRectF = new RectF();
rightRectF.set(width - height, newWidth, width - newWidth, height - newWidth);
resultPath.addArc(rightRectF, -90, 180);
resultPath.lineTo(height / 2f, height - newWidth);
} else if (((type & TYPE_OVAL_TOP) != 0) && (type & TYPE_OVAL_BOTTOM) != 0) {
RectF leftRectF = new RectF();
leftRectF.set(newWidth, newWidth, width - newWidth, width);
resultPath.addArc(leftRectF, 180, 180);
resultPath.lineTo(width - newWidth, height - width / 2f);
RectF rightRectF = new RectF();
rightRectF.set(newWidth, height - width, width - newWidth, height - newWidth);
resultPath.addArc(rightRectF, 0, 180);
resultPath.lineTo(newWidth, width / 2f);
} else if ((type & TYPE_OVAL_LEFT) != 0) {
RectF arcRectF = new RectF();
arcRectF.set(newWidth, newWidth, height, height - newWidth);
resultPath.addArc(arcRectF, 90, 180);
resultPath.lineTo(width - rightTopRadius, newWidth);
resultPath.quadTo(width, newWidth, width - newWidth, rightTopRadius);
resultPath.lineTo(width - newWidth, height - rightBottomRadius);
resultPath.quadTo(width - newWidth, height - newWidth, width - rightBottomRadius, height - newWidth);
resultPath.lineTo(height / 2f, height - newWidth);
} else if ((type & TYPE_OVAL_RIGHT) != 0) {
resultPath.moveTo(leftTopRadius, newWidth);
resultPath.lineTo(width - height / 2f, newWidth);
RectF rightRectF = new RectF();
rightRectF.set(width - height, newWidth, width - newWidth, height - newWidth);
resultPath.addArc(rightRectF, -90, 180);
resultPath.lineTo(leftBottomRadius, height - newWidth);
resultPath.quadTo(newWidth, height - newWidth, newWidth, height - leftBottomRadius);
resultPath.lineTo(newWidth, leftTopRadius);
resultPath.quadTo(newWidth, newWidth, leftTopRadius, newWidth);
} else if ((type & TYPE_OVAL_TOP) != 0) {
RectF arcRectF = new RectF();
arcRectF.set(newWidth, newWidth, width - newWidth, width);
resultPath.addArc(arcRectF, 180, 180);
resultPath.lineTo(width - newWidth, height - rightBottomRadius);
resultPath.quadTo(width - newWidth, height - newWidth, width - rightBottomRadius, height - newWidth);
resultPath.lineTo(leftBottomRadius, height - newWidth);
resultPath.quadTo(newWidth, height - newWidth, newWidth, height - leftBottomRadius);
resultPath.lineTo(newWidth, width / 2f);
} else if ((type & TYPE_OVAL_BOTTOM) != 0) {
resultPath.moveTo(leftTopRadius, newWidth);
resultPath.lineTo(width - rightTopRadius, newWidth);
resultPath.quadTo(width, newWidth, width - newWidth, rightTopRadius);
resultPath.lineTo(width - newWidth, height - width / 2f);
RectF rightRectF = new RectF();
rightRectF.set(newWidth, height - width, width - newWidth, height - newWidth);
resultPath.addArc(rightRectF, 0, 180);
resultPath.lineTo(newWidth, leftTopRadius);
resultPath.quadTo(newWidth, newWidth, leftTopRadius, newWidth);
return calculateRadiusSocketPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height, solidWidth);
private static Path[] calculateRadiusSocketPath(int leftTopRadius, int rightTopRadius,
int leftBottomRadius, int rightBottomRadius,
int width, int height, int solidWidth) {
Path[] result = new Path[2];
Path solidPath = new Path();
Path radiusPath = new Path();
float leftTopRadiusLeft, leftTopRadiusTop;
float leftBottomRadiusLeft, leftBottomRadiusBottom;
float rightTopRadiusRight, rightTopRadiusTop;
float rightBottomRadiusRight, rightBottomRadiusBottom;
int[] sideTop = calculateRadiusLength(leftTopRadius, rightTopRadius, width);
int[] sideBottom = calculateRadiusLength(leftBottomRadius, rightBottomRadius, width);
int[] sideLeft = calculateRadiusLength(leftTopRadius, leftBottomRadius, height);
int[] sideRight = calculateRadiusLength(rightTopRadius, rightBottomRadius, height);
leftTopRadiusTop = sideTop[0];
rightTopRadiusTop = sideTop[1];
leftBottomRadiusBottom = sideBottom[0];
rightBottomRadiusBottom = sideBottom[1];
leftTopRadiusLeft = sideLeft[0];
leftBottomRadiusLeft = sideLeft[1];
rightTopRadiusRight = sideRight[0];
rightBottomRadiusRight = sideRight[1];
float newWidth = solidWidth / 2.0f;
solidPath.moveTo(leftTopRadiusTop, newWidth);
solidPath.lineTo(width - rightTopRadiusTop, newWidth);
solidPath.moveTo(width - newWidth, rightTopRadiusRight);
solidPath.lineTo(width - newWidth, height - rightBottomRadiusRight);
solidPath.moveTo(width - rightBottomRadiusBottom, height - newWidth);
solidPath.lineTo(leftBottomRadiusBottom, height - newWidth);
solidPath.moveTo(newWidth, height - leftBottomRadiusLeft);
solidPath.lineTo(newWidth, leftTopRadiusLeft);
radiusPath.moveTo(newWidth, leftTopRadiusLeft);
radiusPath.quadTo(newWidth, newWidth, leftTopRadiusTop, newWidth);
radiusPath.moveTo(width - rightTopRadiusTop, newWidth);
radiusPath.quadTo(width, newWidth, width - newWidth, rightTopRadiusRight);
radiusPath.moveTo(width - newWidth, height - rightBottomRadiusRight);
radiusPath.quadTo(width - newWidth, height - newWidth, width - rightBottomRadiusBottom, height - newWidth);
radiusPath.moveTo(leftBottomRadiusBottom, height - newWidth);
radiusPath.quadTo(newWidth, height - newWidth, newWidth, height - leftBottomRadiusLeft);
public static Path calculateRectSocketPath(int width, int height, int solidWidth) {
float newWidth = solidWidth / 2.0f;
Path result = new Path();
result.moveTo(newWidth, newWidth);
result.lineTo(width - newWidth, newWidth);
result.lineTo(width - newWidth, height - newWidth);
result.lineTo(newWidth, height - newWidth);
private static int getType(int leftTopRadius, int rightTopRadius,
int leftBottomRadius, int rightBottomRadius,
if (leftTopRadius <= 0 && rightTopRadius <= 0 && leftBottomRadius <= 0 && rightBottomRadius <= 0)
boolean topOval = leftTopRadius + rightTopRadius >= width;
boolean bottomOval = leftBottomRadius + rightBottomRadius >= width;
boolean leftOval = leftTopRadius + leftBottomRadius >= height;
boolean rightOval = rightTopRadius + rightBottomRadius >= height;
if (topOval && bottomOval && leftOval && rightOval)
if (!topOval && !bottomOval && !leftOval && !rightOval)
if ((topOval || bottomOval) && (leftOval || rightOval)) return TYPE_RADIUS;
result |= TYPE_OVAL_BOTTOM;
result |= TYPE_OVAL_LEFT;
result |= TYPE_OVAL_RIGHT;
private static int[] calculateRadiusLength(int sameSide1, int sameSide2, int sameSideWidth) {
int[] result = new int[2];
if (sameSide1 > 0 && sameSide2 > 0) {
int topRadiusWidth = sameSide1 + sameSide2;
if (topRadiusWidth > sameSideWidth) {
result[0] = (int) ((sameSide1 * 1.0 / topRadiusWidth) * sameSideWidth);
result[1] = (int) ((sameSide2 * 1.0 / topRadiusWidth) * sameSideWidth);
} else if (sameSide1 > 0) {
result[0] = Math.min(sameSide1, sameSideWidth);
} else if (sameSide2 > 0) {
result[1] = Math.min(sameSide2, sameSideWidth);
4. 解决锯齿问题 自定义Drawable
RadiusDrawable
public class RadiusDrawable extends Drawable {
private ColorStateList mBgColorsList;
private Shader mBgShader;
private PorterDuffColorFilter mBgTintFilter;
private ColorStateList mBgTint;
private PorterDuff.Mode mBgTintMode;
private boolean mDrawSolid;
private ColorStateList mSolidColorsList;
private Shader mSolidShader;
private Paint mSolidPaint;
private PorterDuffColorFilter mSolidTintFilter;
private ColorStateList mSolidTint;
private PorterDuff.Mode mSolidTintMode;
public RadiusDrawable(ColorStateList bgColorsList, Shader bgShader, Path path) {
this(bgColorsList, bgShader, path, 0, null, null, null, null);
public RadiusDrawable(ColorStateList bgColorsList, Shader bgShader, Path path, int solidWidth, ColorStateList solidColorsList,
Shader solidShader, List solidPath, DashPathEffect dashPathEffect) {
this.mBgTintMode = PorterDuff.Mode.SRC_IN;
this.mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.mBgPaint.setDither(true);
this.mBgShader = bgShader;
this.mDrawSolid = solidWidth > 0;
this.mSolidPath = solidPath ==
null ?
new ArrayList() : solidPath; this.mSolidTintMode = PorterDuff.Mode.SRC_IN;
this.mSolidPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.mSolidPaint.setAntiAlias(true);
this.mSolidPaint.setDither(true);
this.mSolidPaint.setStyle(Paint.Style.STROKE);
this.mSolidPaint.setStrokeWidth(solidWidth);
this.mSolidPaint.setPathEffect(dashPathEffect);
this.mSolidShader = solidShader;
this.setBackground(bgColorsList, solidColorsList);
void setBgShader(Shader shader) {
void setBackground(ColorStateList bgColorsList, ColorStateList solidColorsList) {
this.mBgColorsList = bgColorsList == null ? ColorStateList.valueOf(0) : bgColorsList;
this.mBgPaint.setColor(this.mBgColorsList.getColorForState(this.getState(), this.mBgColorsList.getDefaultColor()));
if (mDrawSolid && mSolidShader == null) {
this.mSolidColorsList = solidColorsList == null ? ColorStateList.valueOf(0) : solidColorsList;
this.mSolidPaint.setColor(this.mSolidColorsList.getColorForState(this.getState(), this.mSolidColorsList.getDefaultColor()));
public void draw(Canvas canvas) {
Paint bgPaint = this.mBgPaint;
boolean bgClearColorFilter = false;
boolean hasBgShader = mBgShader != null;
bgPaint.setShader(mBgShader);
if (this.mBgTintFilter != null) {
bgPaint.setColorFilter(this.mBgTintFilter);
bgClearColorFilter = true;
bgClearColorFilter = false;
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
canvas.drawPath(mBgPath, bgPaint);
if (bgClearColorFilter) {
bgPaint.setColorFilter(null);
Paint solidPaint = this.mSolidPaint;
boolean solidClearColorFilter = false;
boolean hasSolidShader = mSolidShader != null;
solidPaint.setShader(mSolidShader);
if (this.mSolidTintFilter != null) {
solidPaint.setColorFilter(this.mSolidTintFilter);
solidClearColorFilter = true;
solidClearColorFilter = false;
for (Path solidPath : mSolidPath) {
canvas.drawPath(solidPath, solidPaint);
if (solidClearColorFilter) {
solidPaint.setColorFilter(null);
public void setAlpha(int alpha) {
this.mBgPaint.setAlpha(alpha);
this.mSolidPaint.setAlpha(alpha);
public void setColorFilter(ColorFilter cf) {
this.mBgPaint.setColorFilter(cf);
this.mSolidPaint.setColorFilter(cf);
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
public void setColor(@Nullable ColorStateList backgroundColor, @Nullable ColorStateList solidColorsList) {
this.setBackground(backgroundColor, solidColorsList);
public ColorStateList getBackGroundColor() {
return this.mBgColorsList;
public ColorStateList getSolidColor() {
return this.mSolidColorsList;
public void setTintList(ColorStateList tint) {
this.mBgTintFilter = this.createTintFilter(this.mBgTint, this.mBgTintMode);
this.mSolidTintFilter = this.createTintFilter(this.mSolidTint, this.mSolidTintMode);
public void setTintMode(PorterDuff.Mode tintMode) {
this.mBgTintMode = tintMode;
this.mBgTintFilter = this.createTintFilter(this.mBgTint, this.mSolidTintMode);
if (mDrawSolid && mSolidShader == null) {
this.mSolidTintMode = tintMode;
this.mSolidTintFilter = this.createTintFilter(this.mBgTint, this.mSolidTintMode);
protected boolean onStateChange(int[] stateSet) {
boolean bgColorChanged = false;
int newBgColor = this.mBgColorsList.getColorForState(stateSet, this.mBgColorsList.getDefaultColor());
bgColorChanged = newBgColor != this.mBgPaint.getColor();
this.mBgPaint.setColor(newBgColor);
boolean solidColorChanged = false;
if (mDrawSolid && mSolidShader == null) {
int newSolidColor = this.mSolidColorsList.getColorForState(stateSet, this.mSolidColorsList.getDefaultColor());
solidColorChanged = newSolidColor != this.mSolidPaint.getColor();
this.mSolidPaint.setColor(newSolidColor);
if (this.mBgShader == null && this.mBgTint != null && this.mBgTintMode != null) {
this.mBgTintFilter = this.createTintFilter(this.mBgTint, this.mBgTintMode);
} else if (this.mSolidShader == null && this.mSolidTint != null && this.mSolidTintMode != null) {
this.mSolidTintFilter = this.createTintFilter(this.mSolidTint, this.mSolidTintMode);
return bgColorChanged || solidColorChanged;
public boolean isStateful() {
return this.mBgTint != null && this.mBgTint.isStateful()
|| this.mBgColorsList != null && this.mBgColorsList.isStateful()
|| this.mSolidTint != null && this.mSolidTint.isStateful()
|| this.mSolidColorsList != null && this.mSolidColorsList.isStateful()
return this.mBgTint != null && this.mBgTint.isStateful()
|| this.mBgColorsList != null && this.mBgColorsList.isStateful()
private PorterDuffColorFilter createTintFilter(ColorStateList tint, PorterDuff.Mode tintMode) {
if (tint != null && tintMode != null) {
int color = tint.getColorForState(this.getState(), 0);
return new PorterDuffColorFilter(color, tintMode);
4.1创建attrs自定义属性
<declare-styleable name="RadiusView">
<attr name="rv_radius_all" format="dimension" />
<attr name="rv_radius_leftTop" format="dimension" />
<attr name="rv_radius_rightTop" format="dimension" />
<attr name="rv_radius_rightBottom" format="dimension" />
<attr name="rv_radius_leftBottom" format="dimension" />
<attr name="rv_background_color" format="color" />
<attr name="rv_shader_start_color" format="color" />
<attr name="rv_shader_middle_color" format="color" />
<attr name="rv_shader_middle_color2" format="color" />
<attr name="rv_shader_middle_color3" format="color" />
<attr name="rv_shader_end_color" format="color" />
<attr name="rv_shader_type" format="enum">
<enum name="linear" value="10" />
<enum name="radial" value="11" />
<enum name="sweep" value="12" />
<attr name="rv_shader_linear_orientation" format="enum">
<enum name="top_to_bottom" value="110" />
<enum name="bottom_to_top" value="111" />
<enum name="left_to_right" value="220" />
<enum name="right_to_left" value="221" />
<enum name="leftTop_to_rightBottom" value="330" />
<enum name="rightBottom_to_leftTop" value="331" />
<enum name="rightTop_to_leftBottom" value="440" />
<enum name="leftBottom_to_rightTop" value="441" />
<attr name="rv_solid_width" format="dimension" />
<attr name="rv_solid_color" format="color" />
<attr name="rv_solid_dashWidth" format="dimension" />
<attr name="rv_solid_dashGap" format="dimension" />
<attr name="rv_solid_type" format="enum">
<enum name="solid" value="0" />
<enum name="dash" value="1" />
<attr name="rv_solid_shader_start_color" format="color" />
<attr name="rv_solid_shader_middle_color" format="color" />
<attr name="rv_solid_shader_middle_color2" format="color" />
<attr name="rv_solid_shader_middle_color3" format="color" />
<attr name="rv_solid_shader_end_color" format="color" />
<attr name="rv_solid_shader_type" format="enum">
<enum name="linear" value="10" />
<enum name="radial" value="11" />
<enum name="sweep" value="12" />
<attr name="rv_solid_shader_linear_orientation" format="enum">
<enum name="top_to_bottom" value="110" />
<enum name="bottom_to_top" value="111" />
<enum name="left_to_right" value="220" />
<enum name="right_to_left" value="221" />
<enum name="leftTop_to_rightBottom" value="330" />
<enum name="rightBottom_to_leftTop" value="331" />
<enum name="rightTop_to_leftBottom" value="440" />
<enum name="leftBottom_to_rightTop" value="441" />
4.2创建自动适配布局 公共接口IAutoLayout
public interface IAutoLayout {
int AUTO_TYPE_HEIGHT = 1;
@IntDef(value = {AUTO_TYPE_WIDTH, AUTO_TYPE_HEIGHT})
void setAutoViewInfo(int autoWidth, int autoHeight);
void setAutoViewInfo(@AutoType int autoType, int autoWidth, int autoHeight);
4.3创建账单适配布局AutoRelativeLayout
public class AutoRelativeLayout extends RelativeLayout implements IAutoLayout {
private int auto_type = 1;
public AutoRelativeLayout(Context context) {
public AutoRelativeLayout(Context context, AttributeSet attrs) {
public AutoRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public AutoRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
protected void init(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AutoWidthHeightView);
auto_height = typedArray.getInt(R.styleable.AutoWidthHeightView_auto_view_height, 0);
auto_width = typedArray.getInt(R.styleable.AutoWidthHeightView_auto_view_width, 0);
auto_type = typedArray.getInt(R.styleable.AutoWidthHeightView_auto_view_type, -1);
public void setAutoViewInfo(int autoWidth, int autoHeight) {
this.auto_width = autoWidth;
this.auto_height = autoHeight;
public void setAutoViewInfo(@AutoType int autoType, int autoWidth, int autoHeight) {
this.auto_type = autoType;
this.auto_width = autoWidth;
this.auto_height = autoHeight;
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
measureChildren(widthMeasureSpec, heightMeasureSpec);
int viewWidth = getMeasuredWidth();
int viewHeight = getMeasuredHeight();
viewWidth = (int) (viewHeight * ((auto_width * 1.0f) / auto_height));
viewHeight = (int) (viewWidth * ((auto_height * 1.0f) / auto_width));
widthMeasureSpec = MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
其他AutoLinearLayout,AutoImageView,AutoFrameLayout布局
都是一样的
4.4创建自定义布局适配attrs
<declare-styleable name="AutoWidthHeightView">
<attr name="auto_view_width" format="integer" />
<attr name="auto_view_height" format="integer" />
<attr name="auto_view_type" format="enum">
<enum name="auto_view_width" value="0" />
<enum name="auto_view_height" value="1" />
5.圆角相对布局 RadiusRelativeLayout
public class RadiusRelativeLayout extends AutoRelativeLayout implements IRadiusLayout {
private int width, height;
private int leftTopRadius;
private int rightTopRadius;
private int rightBottomRadius;
private int leftBottomRadius;
private RadiusDrawable radiusDrawable;
private ColorStateList bgColorStateList;
private int[] bgShaderColors;
private int bgShaderType;
private int bgShaderLinearOrientation;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
private int[] solidShaderColors;
private int solidShaderType;
private int solidShaderLinearOrientation;
private boolean forceRefreshLayout;
public RadiusRelativeLayout(Context context) {
public RadiusRelativeLayout(Context context, AttributeSet attrs) {
public RadiusRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public RadiusRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
protected void init(Context context, AttributeSet attrs) {
super.init(context, attrs);
if (Build.VERSION.SDK_INT < 18) setLayerType(View.LAYER_TYPE_SOFTWARE, null);
TypedArray radiusType = context.obtainStyledAttributes(attrs, R.styleable.RadiusView);
int radius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_all, DEFAULT_RADIUS);
leftTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftTop, DEFAULT_RADIUS);
rightTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightTop, DEFAULT_RADIUS);
rightBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightBottom, DEFAULT_RADIUS);
leftBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftBottom, DEFAULT_RADIUS);
bgColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_background_color);
int startColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int middleColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int middleColor2 = radiusType.getColor(R.styleable.RadiusView_rv_shader_middle_color2, ShaderUtils.COLOR_VALUE_NONE);
int middleColor3 = radiusType.getColor(R.styleable.RadiusView_rv_shader_middle_color3, ShaderUtils.COLOR_VALUE_NONE);
int endColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
bgShaderType = radiusType.getInt(R.styleable.RadiusView_rv_shader_type, ShaderUtils.SHADER_TYPE_NONE);
bgShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
bgShaderColors = ShaderUtils.createColorsArray(startColor, middleColor, middleColor2, middleColor3, endColor);
if (bgShaderColors == null)
bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
solidWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_width, 0);
solidColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_solid_color);
int dashGap = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashGap, 0);
int dashWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashWidth, 0);
int lineType = radiusType.getInt(R.styleable.RadiusView_rv_solid_type, SOLID_TYPE_SOLID);
int solidStartColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int solidMiddleColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int solidMiddleColor2 = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_middle_color2, ShaderUtils.COLOR_VALUE_NONE);
int solidMiddleColor3 = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_middle_color3, ShaderUtils.COLOR_VALUE_NONE);
int solidEndColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
solidShaderType = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_type, ShaderUtils.SHADER_TYPE_NONE);
solidShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
solidShaderColors = ShaderUtils.createColorsArray(solidStartColor, solidMiddleColor, solidMiddleColor2, solidMiddleColor3, solidEndColor);
if (solidShaderColors == null)
solidShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
if (DEFAULT_RADIUS >= leftTopRadius) leftTopRadius = radius;
if (DEFAULT_RADIUS >= rightTopRadius) rightTopRadius = radius;
if (DEFAULT_RADIUS >= rightBottomRadius) rightBottomRadius = radius;
if (DEFAULT_RADIUS >= leftBottomRadius) leftBottomRadius = radius;
if (bgColorStateList == null) {
bgColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (solidColorStateList == null) {
solidColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (lineType == SOLID_TYPE_DASH) {
dashPathEffect = new DashPathEffect(new float[]{dashWidth, dashGap}, 0);
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
public void setRadius(int radius) {
rightBottomRadius = radius;
leftBottomRadius = radius;
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!changed && !this.forceRefreshLayout) {
this.forceRefreshLayout = false;
final Path bgPath = setBackground();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
setOutlineProvider(new ViewOutlineProvider() {
public void getOutline(View view, Outline outline) {
outline.setConvexPath(bgPath);
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
private Path setBackground() {
Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
Shader solidShader = null;
if (solidShaderType != ShaderUtils.SHADER_TYPE_NONE) {
solidShader = ShaderUtils.createShader(solidShaderType, width, height, solidShaderColors, solidShaderLinearOrientation);
Path[] solidPathArray = RadiusUtils.calculateSocketPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, solidWidth);
List
solidPath = Arrays.asList(solidPathArray); radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath, solidWidth, solidColorStateList, solidShader, solidPath, dashPathEffect);
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
setBackground(radiusDrawable);
6.圆角线性布局 RadiusLinearLayout
public class RadiusLinearLayout extends AutoLinearLayout implements IRadiusLayout {
private int width, height;
private int leftTopRadius;
private int rightTopRadius;
private int rightBottomRadius;
private int leftBottomRadius;
private RadiusDrawable radiusDrawable;
private ColorStateList bgColorStateList;
private int[] bgShaderColors;
private int bgShaderType;
private int bgShaderLinearOrientation;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
private int[] solidShaderColors;
private int solidShaderType;
private int solidShaderLinearOrientation;
private boolean forceRefreshLayout;
public RadiusLinearLayout(Context context) {
public RadiusLinearLayout(Context context, @Nullable AttributeSet attrs) {
public RadiusLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public RadiusLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
protected void init(Context context, AttributeSet attrs) {
super.init(context, attrs);
if (Build.VERSION.SDK_INT < 18) setLayerType(View.LAYER_TYPE_SOFTWARE, null);
TypedArray radiusType = context.obtainStyledAttributes(attrs, R.styleable.RadiusView);
int radius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_all, DEFAULT_RADIUS);
leftTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftTop, DEFAULT_RADIUS);
rightTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightTop, DEFAULT_RADIUS);
rightBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightBottom, DEFAULT_RADIUS);
leftBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftBottom, DEFAULT_RADIUS);
bgColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_background_color);
int startColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int middleColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int endColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
bgShaderType = radiusType.getInt(R.styleable.RadiusView_rv_shader_type, ShaderUtils.SHADER_TYPE_NONE);
bgShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
bgShaderColors = ShaderUtils.createColorsArray(startColor, middleColor, endColor);
if (bgShaderColors == null)
bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
solidWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_width, 0);
solidColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_solid_color);
int dashGap = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashGap, 0);
int dashWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashWidth, 0);
int lineType = radiusType.getInt(R.styleable.RadiusView_rv_solid_type, SOLID_TYPE_SOLID);
int solidStartColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int solidMiddleColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int solidEndColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
solidShaderType = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_type, ShaderUtils.SHADER_TYPE_NONE);
solidShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
solidShaderColors = ShaderUtils.createColorsArray(solidStartColor, solidMiddleColor, solidEndColor);
if (solidShaderColors == null)
solidShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
if (DEFAULT_RADIUS >= leftTopRadius) leftTopRadius = radius;
if (DEFAULT_RADIUS >= rightTopRadius) rightTopRadius = radius;
if (DEFAULT_RADIUS >= rightBottomRadius) rightBottomRadius = radius;
if (DEFAULT_RADIUS >= leftBottomRadius) leftBottomRadius = radius;
if (bgColorStateList == null) {
bgColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (solidColorStateList == null) {
solidColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (lineType == SOLID_TYPE_DASH) {
dashPathEffect = new DashPathEffect(new float[]{dashWidth, dashGap}, 0);
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
public void setRadius(int radius) {
rightBottomRadius = radius;
leftBottomRadius = radius;
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!changed && !this.forceRefreshLayout) {
this.forceRefreshLayout = false;
final Path bgPath = setBackground();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
setOutlineProvider(new ViewOutlineProvider() {
public void getOutline(View view, Outline outline) {
outline.setConvexPath(bgPath);
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
private Path setBackground() {
Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
Shader solidShader = null;
if (solidShaderType != ShaderUtils.SHADER_TYPE_NONE) {
solidShader = ShaderUtils.createShader(solidShaderType, width, height, solidShaderColors, solidShaderLinearOrientation);
Path[] solidPathArray = RadiusUtils.calculateSocketPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, solidWidth);
List
solidPath = Arrays.asList(solidPathArray); radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath, solidWidth, solidColorStateList, solidShader, solidPath, dashPathEffect);
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
setBackground(radiusDrawable);
7.圆角TextView RadiusTextView
public class RadiusTextView extends AppCompatTextView implements IRadiusLayout {
private int width, height;
private int leftTopRadius;
private int rightTopRadius;
private int rightBottomRadius;
private int leftBottomRadius;
private RadiusDrawable radiusDrawable;
private ColorStateList bgColorStateList;
private int[] bgShaderColors;
private int bgShaderType;
private int bgShaderLinearOrientation;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
private int[] solidShaderColors;
private int solidShaderType;
private int solidShaderLinearOrientation;
private boolean forceRefreshLayout;
public RadiusTextView(Context context) {
public RadiusTextView(Context context, AttributeSet attrs) {
public RadiusTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
protected void init(Context context, AttributeSet attrs) {
if (Build.VERSION.SDK_INT < 18) setLayerType(View.LAYER_TYPE_SOFTWARE, null);
TypedArray radiusType = context.obtainStyledAttributes(attrs, R.styleable.RadiusView);
int radius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_all, DEFAULT_RADIUS);
leftTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftTop, DEFAULT_RADIUS);
rightTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightTop, DEFAULT_RADIUS);
rightBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightBottom, DEFAULT_RADIUS);
leftBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftBottom, DEFAULT_RADIUS);
bgColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_background_color);
int startColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int middleColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int endColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
bgShaderType = radiusType.getInt(R.styleable.RadiusView_rv_shader_type, ShaderUtils.SHADER_TYPE_NONE);
bgShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
bgShaderColors = ShaderUtils.createColorsArray(startColor, middleColor, endColor);
if (bgShaderColors == null)
bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
solidWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_width, 0);
solidColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_solid_color);
int dashGap = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashGap, 0);
int dashWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashWidth, 0);
int lineType = radiusType.getInt(R.styleable.RadiusView_rv_solid_type, SOLID_TYPE_SOLID);
int solidStartColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int solidMiddleColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int solidEndColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
solidShaderType = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_type, ShaderUtils.SHADER_TYPE_NONE);
solidShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
solidShaderColors = ShaderUtils.createColorsArray(solidStartColor, solidMiddleColor, solidEndColor);
if (solidShaderColors == null)
solidShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
if (DEFAULT_RADIUS >= leftTopRadius) leftTopRadius = radius;
if (DEFAULT_RADIUS >= rightTopRadius) rightTopRadius = radius;
if (DEFAULT_RADIUS >= rightBottomRadius) rightBottomRadius = radius;
if (DEFAULT_RADIUS >= leftBottomRadius) leftBottomRadius = radius;
if (bgColorStateList == null) {
bgColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (solidColorStateList == null) {
solidColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (lineType == SOLID_TYPE_DASH) {
dashPathEffect = new DashPathEffect(new float[]{dashWidth, dashGap}, 0);
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
public void setRadius(int radius) {
rightBottomRadius = radius;
leftBottomRadius = radius;
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!changed && !this.forceRefreshLayout) {
this.forceRefreshLayout = false;
final Path bgPath = setBackground();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
setOutlineProvider(new ViewOutlineProvider() {
public void getOutline(View view, Outline outline) {
outline.setConvexPath(bgPath);
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
private Path setBackground() {
Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
Shader solidShader = null;
if (solidShaderType != ShaderUtils.SHADER_TYPE_NONE) {
solidShader = ShaderUtils.createShader(solidShaderType, width, height, solidShaderColors, solidShaderLinearOrientation);
Path[] solidPathArray = RadiusUtils.calculateSocketPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, solidWidth);
List
solidPath = Arrays.asList(solidPathArray); radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath, solidWidth, solidColorStateList, solidShader, solidPath, dashPathEffect);
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
setBackground(radiusDrawable);
8.圆角Image RadiusImageView
public class RadiusImageView extends AutoImageView {
private final int DEFAULT_RADIUS = 0;
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
private static final int COLOR_DRAWABLE_DIMENSION = 2;
public static final int TYPE_SOLID = 0;
public static final int TYPE_DASH = 1;
private int width, height;
private int leftTopRadius;
private int rightTopRadius;
private int rightBottomRadius;
private int leftBottomRadius;
private Paint bitmapPaint;
private Paint solidPaint;
private BitmapShader bitmapShader;
private boolean forceRefreshLayout;
public RadiusImageView(Context context) {
public RadiusImageView(Context context, AttributeSet attrs) {
public RadiusImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
protected void init(Context context, AttributeSet attrs) {
super.init(context, attrs);
if (Build.VERSION.SDK_INT < 18) setLayerType(View.LAYER_TYPE_SOFTWARE, null);
TypedArray radiusType = context.obtainStyledAttributes(attrs, R.styleable.RadiusView);
int radius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_all, DEFAULT_RADIUS);
leftTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftTop, DEFAULT_RADIUS);
rightTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightTop, DEFAULT_RADIUS);
rightBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightBottom, DEFAULT_RADIUS);
leftBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftBottom, DEFAULT_RADIUS);
solidWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_width, 0);
solidColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_color, Color.TRANSPARENT);
int dashGap = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashGap, 0);
int dashWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashWidth, 0);
int lineType = radiusType.getInt(R.styleable.RadiusView_rv_solid_type, TYPE_SOLID);
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
if (DEFAULT_RADIUS >= leftTopRadius) leftTopRadius = radius;
if (DEFAULT_RADIUS >= rightTopRadius) rightTopRadius = radius;
if (DEFAULT_RADIUS >= rightBottomRadius) rightBottomRadius = radius;
if (DEFAULT_RADIUS >= leftBottomRadius) leftBottomRadius = radius;
bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bitmapPaint.setDither(true);
solidPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
solidPaint.setDither(true);
solidPaint.setStyle(Paint.Style.STROKE);
solidPaint.setColor(solidColor);
solidPaint.setStrokeWidth(solidWidth);
if (lineType == TYPE_SOLID) {
setLineTypeStyle(TYPE_SOLID, 0, 0, false);
setLineTypeStyle(TYPE_DASH, dashGap, dashWidth, false);
private void setLineTypeStyle(int lineType, float dashGap, float dashWidth, boolean invalidate) {
if (lineType == TYPE_DASH) {
DashPathEffect dashPathEffect = null;
dashPathEffect = new DashPathEffect(new float[]{dashWidth, dashGap}, 0);
solidPaint.setPathEffect(dashPathEffect);
solidPaint.setPathEffect(null);
if (invalidate) invalidate();
public void setSolidColor(int color) {
solidPaint.setColor(color);
public void setRadius(int radius) {
rightBottomRadius = radius;
leftBottomRadius = radius;
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!changed && !this.forceRefreshLayout) {
this.forceRefreshLayout = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
setOutlineProvider(new ViewOutlineProvider() {
public void getOutline(View view, Outline outline) {
Path path = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height, false);
outline.setConvexPath(path);
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
protected void onDraw(Canvas canvas) {
if (leftTopRadius <= DEFAULT_RADIUS && leftBottomRadius <= DEFAULT_RADIUS &&
rightTopRadius <= DEFAULT_RADIUS && rightBottomRadius <= DEFAULT_RADIUS) {
canvas.drawPath(RadiusUtils.calculateRectSocketPath(width, height, solidWidth), solidPaint);
Path path = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height);
Bitmap bitmap = getBitmapFromDrawable(getDrawable());
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
configureBounds(getDrawable());
bitmapShader.setLocalMatrix(matrix);
bitmapPaint.setShader(bitmapShader);
canvas.drawPath(path, bitmapPaint);
Path[] result = RadiusUtils.calculateSocketPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height, solidWidth);
canvas.drawPath(result[0], solidPaint);
canvas.drawPath(result[1], solidPaint);
private Bitmap getBitmapFromDrawable(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLOR_DRAWABLE_DIMENSION, COLOR_DRAWABLE_DIMENSION, BITMAP_CONFIG);
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
private void configureBounds(Drawable drawable) {
final ImageView.ScaleType scaleType = getScaleType();
final int intrinsicWidth = drawable.getIntrinsicWidth();
final int intrinsicHeight = drawable.getIntrinsicHeight();
final int vWidth = width - getPaddingLeft() - getPaddingRight();
final int vHeight = height - getPaddingTop() - getPaddingBottom();
final boolean fits = (intrinsicWidth < 0 || vWidth == intrinsicWidth)
&& (intrinsicHeight < 0 || vHeight == intrinsicHeight);
if (intrinsicWidth <= 0 || intrinsicHeight <= 0 || ImageView.ScaleType.FIT_XY == scaleType) {
if (ImageView.ScaleType.MATRIX == scaleType) {
} else if (ImageView.ScaleType.CENTER == scaleType) {
matrix.setTranslate(Math.round((vWidth - intrinsicWidth) * 0.5f),
Math.round((vHeight - intrinsicHeight) * 0.5f));
} else if (ImageView.ScaleType.CENTER_CROP == scaleType) {
if (intrinsicWidth * vHeight > vWidth * intrinsicHeight) {
scale = (float) vHeight / (float) intrinsicHeight;
dx = (vWidth - intrinsicWidth * scale) * 0.5f;
scale = (float) vWidth / (float) intrinsicWidth;
dy = (vHeight - intrinsicHeight * scale) * 0.5f;
matrix.setScale(scale, scale);
matrix.postTranslate(Math.round(dx), Math.round(dy));
} else if (ImageView.ScaleType.CENTER_INSIDE == scaleType) {
if (intrinsicWidth <= vWidth && intrinsicHeight <= vHeight) {
scale = Math.min((float) vWidth / (float) intrinsicWidth,
(float) vHeight / (float) intrinsicHeight);
dx = Math.round((vWidth - intrinsicWidth * scale) * 0.5f);
dy = Math.round((vHeight - intrinsicHeight * scale) * 0.5f);
matrix.setScale(scale, scale);
matrix.postTranslate(dx, dy);
RectF mTempSrc = new RectF();
RectF mTempDst = new RectF();
mTempSrc.set(0, 0, intrinsicWidth, intrinsicHeight);
mTempDst.set(0, 0, vWidth, vHeight);
matrix.setRectToRect(mTempSrc, mTempDst, Matrix.ScaleToFit.CENTER);
9.圆角FrameLayout RadiusFrameLayout
public class RadiusFrameLayout extends AutoFrameLayout implements IRadiusLayout{
private int width, height;
private int leftTopRadius;
private int rightTopRadius;
private int rightBottomRadius;
private int leftBottomRadius;
private RadiusDrawable radiusDrawable;
private ColorStateList bgColorStateList;
private int[] bgShaderColors;
private int bgShaderType;
private int bgShaderLinearOrientation;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
private int[] solidShaderColors;
private int solidShaderType;
private int solidShaderLinearOrientation;
private boolean forceRefreshLayout;
public RadiusFrameLayout(Context context) {
public RadiusFrameLayout(Context context, AttributeSet attrs) {
public RadiusFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public RadiusFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
protected void init(Context context, AttributeSet attrs) {
super.init(context, attrs);
if (Build.VERSION.SDK_INT < 18) setLayerType(View.LAYER_TYPE_SOFTWARE, null);
TypedArray radiusType = context.obtainStyledAttributes(attrs, R.styleable.RadiusView);
int radius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_all, DEFAULT_RADIUS);
leftTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftTop, DEFAULT_RADIUS);
rightTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightTop, DEFAULT_RADIUS);
rightBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightBottom, DEFAULT_RADIUS);
leftBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftBottom, DEFAULT_RADIUS);
bgColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_background_color);
int startColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int middleColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int endColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
bgShaderType = radiusType.getInt(R.styleable.RadiusView_rv_shader_type, ShaderUtils.SHADER_TYPE_NONE);
bgShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
bgShaderColors = ShaderUtils.createColorsArray(startColor, middleColor, endColor);
if (bgShaderColors == null)
bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
solidWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_width, 0);
solidColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_solid_color);
int dashGap = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashGap, 0);
int dashWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashWidth, 0);
int lineType = radiusType.getInt(R.styleable.RadiusView_rv_solid_type, SOLID_TYPE_SOLID);
int solidStartColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int solidMiddleColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int solidEndColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
solidShaderType = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_type, ShaderUtils.SHADER_TYPE_NONE);
solidShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
solidShaderColors = ShaderUtils.createColorsArray(solidStartColor, solidMiddleColor, solidEndColor);
if (solidShaderColors == null)
solidShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
if (DEFAULT_RADIUS >= leftTopRadius) leftTopRadius = radius;
if (DEFAULT_RADIUS >= rightTopRadius) rightTopRadius = radius;
if (DEFAULT_RADIUS >= rightBottomRadius) rightBottomRadius = radius;
if (DEFAULT_RADIUS >= leftBottomRadius) leftBottomRadius = radius;
if (bgColorStateList == null) {
bgColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (solidColorStateList == null) {
solidColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (lineType == SOLID_TYPE_DASH) {
dashPathEffect = new DashPathEffect(new float[]{dashWidth, dashGap}, 0);
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
public void setRadius(int radius) {
rightBottomRadius = radius;
leftBottomRadius = radius;
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!changed && !this.forceRefreshLayout) {
this.forceRefreshLayout = false;
final Path bgPath = setBackground();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
setOutlineProvider(new ViewOutlineProvider() {
public void getOutline(View view, Outline outline) {
outline.setConvexPath(bgPath);
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
private Path setBackground() {
final Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
Shader solidShader = null;
if (solidShaderType != ShaderUtils.SHADER_TYPE_NONE) {
solidShader = ShaderUtils.createShader(solidShaderType, width, height, solidShaderColors, solidShaderLinearOrientation);
Path[] solidPathArray = RadiusUtils.calculateSocketPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, solidWidth);
List
solidPath = Arrays.asList(solidPathArray); radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath, solidWidth, solidColorStateList, solidShader, solidPath, dashPathEffect);
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
setBackground(radiusDrawable);
10.圆角EditText RadiusEditText
public class RadiusEditText extends ClearAbleEditText implements IRadiusLayout {
private int width, height;
private int leftTopRadius;
private int rightTopRadius;
private int rightBottomRadius;
private int leftBottomRadius;
private RadiusDrawable radiusDrawable;
private ColorStateList bgColorStateList;
private int[] bgShaderColors;
private int bgShaderType;
private int bgShaderLinearOrientation;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
private int[] solidShaderColors;
private int solidShaderType;
private int solidShaderLinearOrientation;
private boolean forceRefreshLayout;
public RadiusEditText(Context context) {
public RadiusEditText(Context context, AttributeSet attrs) {
public RadiusEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
protected void init(Context context, AttributeSet attrs) {
setFocusableInTouchMode(true);
if (Build.VERSION.SDK_INT < 18) setLayerType(View.LAYER_TYPE_SOFTWARE, null);
TypedArray radiusType = context.obtainStyledAttributes(attrs, R.styleable.RadiusView);
int radius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_all, DEFAULT_RADIUS);
leftTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftTop, DEFAULT_RADIUS);
rightTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightTop, DEFAULT_RADIUS);
rightBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightBottom, DEFAULT_RADIUS);
leftBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftBottom, DEFAULT_RADIUS);
bgColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_background_color);
int startColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int middleColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int endColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
bgShaderType = radiusType.getInt(R.styleable.RadiusView_rv_shader_type, ShaderUtils.SHADER_TYPE_NONE);
bgShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
bgShaderColors = ShaderUtils.createColorsArray(startColor, middleColor, endColor);
if (bgShaderColors == null)
bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
solidWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_width, 0);
solidColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_solid_color);
int dashGap = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashGap, 0);
int dashWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashWidth, 0);
int lineType = radiusType.getInt(R.styleable.RadiusView_rv_solid_type, SOLID_TYPE_SOLID);
int solidStartColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int solidMiddleColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int solidEndColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
solidShaderType = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_type, ShaderUtils.SHADER_TYPE_NONE);
solidShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
solidShaderColors = ShaderUtils.createColorsArray(solidStartColor, solidMiddleColor, solidEndColor);
if (solidShaderColors == null)
solidShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
if (DEFAULT_RADIUS >= leftTopRadius) leftTopRadius = radius;
if (DEFAULT_RADIUS >= rightTopRadius) rightTopRadius = radius;
if (DEFAULT_RADIUS >= rightBottomRadius) rightBottomRadius = radius;
if (DEFAULT_RADIUS >= leftBottomRadius) leftBottomRadius = radius;
if (bgColorStateList == null) {
bgColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (solidColorStateList == null) {
solidColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (lineType == SOLID_TYPE_DASH) {
dashPathEffect = new DashPathEffect(new float[]{dashWidth, dashGap}, 0);
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
public void setRadius(int radius) {
rightBottomRadius = radius;
leftBottomRadius = radius;
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!changed && !this.forceRefreshLayout) {
this.forceRefreshLayout = false;
final Path bgPath = setBackground();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
setOutlineProvider(new ViewOutlineProvider() {
public void getOutline(View view, Outline outline) {
outline.setConvexPath(bgPath);
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
private Path setBackground() {
Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
Shader solidShader = null;
if (solidShaderType != ShaderUtils.SHADER_TYPE_NONE) {
solidShader = ShaderUtils.createShader(solidShaderType, width, height, solidShaderColors, solidShaderLinearOrientation);
Path[] solidPathArray = RadiusUtils.calculateSocketPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, solidWidth);
List
solidPath = Arrays.asList(solidPathArray); radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath, solidWidth, solidColorStateList, solidShader, solidPath, dashPathEffect);
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
setBackground(radiusDrawable);
11.圆角Button RadiusButton
public class RadiusButton extends AppCompatButton implements IRadiusLayout {
private int width, height;
private int leftTopRadius;
private int rightTopRadius;
private int rightBottomRadius;
private int leftBottomRadius;
private RadiusDrawable radiusDrawable;
private ColorStateList bgColorStateList;
private int[] bgShaderColors;
private int bgShaderType;
private int bgShaderLinearOrientation;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
private int[] solidShaderColors;
private int solidShaderType;
private int solidShaderLinearOrientation;
private boolean forceRefreshLayout;
public RadiusButton(Context context) {
public RadiusButton(Context context, AttributeSet attrs) {
public RadiusButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
protected void init(Context context, AttributeSet attrs) {
if (Build.VERSION.SDK_INT < 18) setLayerType(View.LAYER_TYPE_SOFTWARE, null);
TypedArray radiusType = context.obtainStyledAttributes(attrs, R.styleable.RadiusView);
int radius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_all, DEFAULT_RADIUS);
leftTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftTop, DEFAULT_RADIUS);
rightTopRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightTop, DEFAULT_RADIUS);
rightBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_rightBottom, DEFAULT_RADIUS);
leftBottomRadius = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_radius_leftBottom, DEFAULT_RADIUS);
bgColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_background_color);
int startColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int middleColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int endColor = radiusType.getColor(R.styleable.RadiusView_rv_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
bgShaderType = radiusType.getInt(R.styleable.RadiusView_rv_shader_type, ShaderUtils.SHADER_TYPE_NONE);
bgShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
bgShaderColors = ShaderUtils.createColorsArray(startColor, middleColor, endColor);
if (bgShaderColors == null)
bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
solidWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_width, 0);
solidColorStateList = radiusType.getColorStateList(R.styleable.RadiusView_rv_solid_color);
int dashGap = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashGap, 0);
int dashWidth = radiusType.getDimensionPixelSize(R.styleable.RadiusView_rv_solid_dashWidth, 0);
int lineType = radiusType.getInt(R.styleable.RadiusView_rv_solid_type, SOLID_TYPE_SOLID);
int solidStartColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_start_color, ShaderUtils.COLOR_VALUE_NONE);
int solidMiddleColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_middle_color, ShaderUtils.COLOR_VALUE_NONE);
int solidEndColor = radiusType.getColor(R.styleable.RadiusView_rv_solid_shader_end_color, ShaderUtils.COLOR_VALUE_NONE);
solidShaderType = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_type, ShaderUtils.SHADER_TYPE_NONE);
solidShaderLinearOrientation = radiusType.getInt(R.styleable.RadiusView_rv_solid_shader_linear_orientation, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
solidShaderColors = ShaderUtils.createColorsArray(solidStartColor, solidMiddleColor, solidEndColor);
if (solidShaderColors == null)
solidShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
if (DEFAULT_RADIUS >= leftTopRadius) leftTopRadius = radius;
if (DEFAULT_RADIUS >= rightTopRadius) rightTopRadius = radius;
if (DEFAULT_RADIUS >= rightBottomRadius) rightBottomRadius = radius;
if (DEFAULT_RADIUS >= leftBottomRadius) leftBottomRadius = radius;
if (bgColorStateList == null) {
bgColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (solidColorStateList == null) {
solidColorStateList = ColorStateList.valueOf(Color.TRANSPARENT);
if (lineType == SOLID_TYPE_DASH) {
dashPathEffect = new DashPathEffect(new float[]{dashWidth, dashGap}, 0);
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
public void setRadius(int radius) {
rightBottomRadius = radius;
leftBottomRadius = radius;
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!changed && !this.forceRefreshLayout) {
this.forceRefreshLayout = false;
final Path bgPath = setBackground();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
setOutlineProvider(new ViewOutlineProvider() {
public void getOutline(View view, Outline outline) {
outline.setConvexPath(bgPath);
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
private Path setBackground() {
Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
Shader solidShader = null;
if (solidShaderType != ShaderUtils.SHADER_TYPE_NONE) {
solidShader = ShaderUtils.createShader(solidShaderType, width, height, solidShaderColors, solidShaderLinearOrientation);
Path[] solidPathArray = RadiusUtils.calculateSocketPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, solidWidth);
List
solidPath = Arrays.asList(solidPathArray); radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath, solidWidth, solidColorStateList, solidShader, solidPath, dashPathEffect);
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
setBackground(radiusDrawable);
12.代码使用样式
<com.sc.scxm.cs.radius.RadiusRelativeLayout
android:layout_centerInParent="true"
android:layout_width="@dimen/dp_100"
android:layout_height="@dimen/dp_100"
app:rv_radius_all="@dimen/dp_10"
app:rv_background_color="@color/colorAccent"
app:rv_solid_width="@dimen/dp_1"
app:rv_solid_shader_start_color="#CDBC78"
app:rv_solid_shader_middle_color="#F5FFE3"
app:rv_solid_shader_middle_color2="#CCBA77"
app:rv_solid_shader_middle_color3="@color/white"
app:rv_solid_shader_end_color="#DDC66D"
app:rv_solid_shader_type="linear"