1.定义全部圆角的通用接口
public interface IRadiusLayout {
int DEFAULT_RADIUS = 0; // 默认没有圆角
int SOLID_TYPE_SOLID = 0; // 实线
int SOLID_TYPE_DASH = 1; // 虚线
/**
* 设置背景颜色状态列表
*
* @param bgColorStateList 背景颜色状态列表
*/
void setBackgroundColor(ColorStateList bgColorStateList);
/**
* 设置边框虚线样式
*
* @param dashPathEffect 边框虚线样式
*/
void setSolidDashPathEffect(DashPathEffect dashPathEffect);
/**
* 设置边框线颜色
*
* @param color 边框线颜色
*/
void setSolidColor(int color);
/**
* 设置边框颜色状态列表
*
* @param solidColorStateList 边框颜色状态列表
*/
void setSolidColor(ColorStateList solidColorStateList);
/**
* 设置圆角,四个圆角大小一样
*
* @param radius 圆角大小
*/
void setRadius(int radius);
/**
* 设置圆角大小,分别设置
*
* @param leftTopRadius 左上角圆角大小
* @param rightTopRadius 右上角圆角大小
* @param rightBottomRadius 左下角圆角大小
* @param leftBottomRadius 右下角圆角大小
*/
void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius);
/**
* 设置左上角圆角大小
*
* @param leftTopRadius 左上角圆角大小
*/
void setLeftTopRadius(int leftTopRadius);
/**
* 设置右上角圆角大小
*
* @param rightTopRadius 右上角圆角大小
*/
void setRightTopRadius(int rightTopRadius);
/**
* 设置右下角圆角大小
*
* @param rightBottomRadius 右下角圆角大小
*/
void setRightBottomRadius(int rightBottomRadius);
/**
* 设置左下角圆角大小
*
* @param leftBottomRadius 左下角圆角大小
*/
void setLeftBottomRadius(int leftBottomRadius);
/**
* 设置背景渐变信息
*
* @param shapeType 渐变类型
* @param shapeColors 渐变颜色数组
*/
void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors);
/**
* 设置背景渐变信息
*
* @param shapeType 渐变类型
* @param shapeColors 渐变颜色数组
* @param shaderLinearOrientation 渐变方向
*/
void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation);
/**
* 设置边框渐变信息
*
* @param shapeType 渐变类型
* @param shapeColors 渐变颜色数组
*/
void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors);
/**
* 设置边框渐变信息
*
* @param shapeType 渐变类型
* @param shapeColors 渐变颜色数组
* @param shaderLinearOrientation 渐变方向
*/
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 {
}
private ShaderUtils() {
}
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);
} else {
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);
} else {
linearGradient = new LinearGradient(halfWidth, 0, halfWidth, height, colors, null, Shader.TileMode.CLAMP);
}
return linearGradient;
}
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) {
colors.add(startColor);
}
if (middleColor != COLOR_VALUE_NONE) {
colors.add(middleColor);
}
if (middleColor2 != COLOR_VALUE_NONE) {
colors.add(middleColor2);
}
if (middleColor3 != COLOR_VALUE_NONE) {
colors.add(middleColor3);
}
if (endColor != COLOR_VALUE_NONE) {
colors.add(endColor);
}
if (colors.size() > 0) {
int[] shaderColors = new int[colors.size()];
for (int i = 0; i < colors.size(); i++) {
shaderColors[i] = colors.get(i);
}
return shaderColors;
}
return null;
}
public static int[] createColorsArray(int startColor, int middleColor, int endColor) {
List colors = new ArrayList<>();
if (startColor != COLOR_VALUE_NONE) {
colors.add(startColor);
}
if (middleColor != COLOR_VALUE_NONE) {
colors.add(middleColor);
}
if (endColor != COLOR_VALUE_NONE) {
colors.add(endColor);
}
if (colors.size() > 0) {
int[] shaderColors = new int[colors.size()];
for (int i = 0; i < colors.size(); i++) {
shaderColors[i] = colors.get(i);
}
return shaderColors;
}
return null;
}
}
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; // 下边为椭圆
/**
* 计算背景路径 ConvexPath
* ConvexPath 这里简单理解:圆角矩形的圆角度数大于矩形的高度或宽度(上下圆角度数的边长和大于高度或者左右圆角度数的边长大于高度,那么就不是 ConvexPath 了)
*
* @param leftTopRadius 左上角圆角大小
* @param rightTopRadius 右上角圆角大小
* @param leftBottomRadius 左下角圆角大小
* @param rightBottomRadius 右下角圆角大小
* @param width 矩形宽
* @param height 矩形高
* @return 结果Path
*/
public static Path calculateBgPath(int leftTopRadius, int rightTopRadius,
int leftBottomRadius, int rightBottomRadius,
int width, int height) {
return calculateBgPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height, true);
}
/**
* 计算背景路径 ConvexPath
* ConvexPath 这里简单理解:圆角矩形的圆角度数大于矩形的高度或宽度(上下圆角度数的边长和大于高度或者左右圆角度数的边长大于高度,那么就不是 ConvexPath 了)
*
* @param leftTopRadius 左上角圆角大小
* @param rightTopRadius 右上角圆角大小
* @param leftBottomRadius 左下角圆角大小
* @param rightBottomRadius 右下角圆角大小
* @param width 矩形宽
* @param height 矩形高
* @param isGetType 是否需要判断类型,当为 true 时可能返回非 Convex Path
* @return 结果Path
*/
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);
if (isGetType) {
int type = getType(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height);
if (type == TYPE_NONE)
return calculateRectBgPath(width, height);
if (type == TYPE_RADIUS)
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);
return resultPath;
}
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);
} else {
return calculateRadiusBgPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height);
}
return resultPath;
}
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);
return resultPath;
}
/**
* 计算直角矩形背景路径
*
* @param width 宽
* @param height 高
*/
private static Path calculateRectBgPath(int width, int height) {
Path result = new Path();
result.moveTo(0, 0);
result.lineTo(width, 0);
result.lineTo(width, height);
result.lineTo(0, height);
result.close();
return result;
}
/**
* 计算边框的边框路径 ConvexPath
* ConvexPath 这里简单理解:圆角矩形的圆角度数大于矩形的高度或宽度(上下圆角度数的边长和大于高度或者左右圆角度数的边长大于高度,那么就不是 ConvexPath 了)
*
* @param leftTopRadius 左上角圆角大小
* @param rightTopRadius 右上角圆角大小
* @param leftBottomRadius 左下角圆角大小
* @param rightBottomRadius 右下角圆角大小
* @param width 矩形宽
* @param height 矩形高
* @param solidWidth 边框宽度
* @return 结果Path 数组,path[0]:四条边 path[1]:四个角的路径
*/
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);
if (type == TYPE_NONE)
return new Path[]{calculateRectSocketPath(width, height, solidWidth)};
if (type == TYPE_RADIUS)
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);
result[0] = resultPath;
return result;
}
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);
} else {
return calculateRadiusSocketPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height, solidWidth);
}
result[0] = resultPath;
return result;
}
/**
* 计算圆角矩形的边框路径
*/
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);
result[0] = solidPath;
result[1] = radiusPath;
return result;
}
/**
* 计算直角矩形边框路径
*
* @param width 宽
* @param height 高
* @param solidWidth 线宽
* @return
*/
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);
result.close();
return result;
}
/**
* 根据圆角大小和边框长度将圆角矩形作为什么图形处理
*
* @return TYPE_CIRCLE:圆形 TYPE_RADIUS:圆角矩形 TYPE_OVAL:两端作为椭圆
*/
private static int getType(int leftTopRadius, int rightTopRadius,
int leftBottomRadius, int rightBottomRadius,
int width, int height) {
// 没有圆角
if (leftTopRadius <= 0 && rightTopRadius <= 0 && leftBottomRadius <= 0 && rightBottomRadius <= 0)
return TYPE_NONE;
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)
return TYPE_CIRCLE;
// 变为圆角矩形
if (!topOval && !bottomOval && !leftOval && !rightOval)
return TYPE_RADIUS;
if ((topOval || bottomOval) && (leftOval || rightOval)) return TYPE_RADIUS;
// 处理半圆
int result = TYPE_NONE;
if (topOval) {
result |= TYPE_OVAL_TOP;
}
if (bottomOval) {
result |= TYPE_OVAL_BOTTOM;
}
if (leftOval) {
result |= TYPE_OVAL_LEFT;
}
if (rightOval) {
result |= TYPE_OVAL_RIGHT;
}
return result;
}
/**
* 根据同边的两个圆角的分别长度和边的长度,重新计算两个圆角该有的长度(防止两个圆角的同边长度之后大于总的长度)
* 如:给出左上角上边的长度和右上角上边的长度,以及矩形的上边边长(矩形的长),重新计算出左上角上边的长度和右上角上边的长度,
* 防止左上角上边的长度和右上角上边的长度之和大于边长导致出错,如果大于边长时,根据比例计算。
*
* @param sameSide1 同边第一个值的原大小
* @param sameSide2 同边第二个值的原大小
* @param sameSideWidth 同边长度
* @return int[],长度为2,int[0]:同边第一个值的最终大小 int[1]:同边第二个值的最终大小
*/
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 {
result[0] = sameSide1;
result[1] = sameSide2;
}
} else if (sameSide1 > 0) {
result[0] = Math.min(sameSide1, sameSideWidth);
} else if (sameSide2 > 0) {
result[1] = Math.min(sameSide2, sameSideWidth);
}
return result;
}
}
4. 解决锯齿问题 自定义Drawable
RadiusDrawable
public class RadiusDrawable extends Drawable {
// 背景颜色相关
private ColorStateList mBgColorsList;
private Shader mBgShader; // 渐变优先级更高
private Path mBgPath;
private Paint mBgPaint;
private PorterDuffColorFilter mBgTintFilter;
private ColorStateList mBgTint;
private PorterDuff.Mode mBgTintMode;
// 边框线相关
private boolean mDrawSolid;
private ColorStateList mSolidColorsList;
private Shader mSolidShader; // 渐变优先级更高
private List mSolidPath;
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.mBgPath = path;
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;
if (mDrawSolid) {
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) {
if (shader != null) {
this.mBgShader = shader;
this.invalidateSelf();
}
}
void setBackground(ColorStateList bgColorsList, ColorStateList solidColorsList) {
if (mBgShader == null) {
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()));
}
}
@Override
public void draw(Canvas canvas) {
Paint bgPaint = this.mBgPaint;
boolean bgClearColorFilter = false;
boolean hasBgShader = mBgShader != null;
if (hasBgShader) {
bgPaint.setShader(mBgShader);
} else {
if (this.mBgTintFilter != null) {
bgPaint.setColorFilter(this.mBgTintFilter);
bgClearColorFilter = true;
} else {
bgClearColorFilter = false;
}
}
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
canvas.drawPath(mBgPath, bgPaint);
if (bgClearColorFilter) {
bgPaint.setColorFilter(null);
}
if (mDrawSolid) {
Paint solidPaint = this.mSolidPaint;
boolean solidClearColorFilter = false;
boolean hasSolidShader = mSolidShader != null;
if (hasSolidShader) {
solidPaint.setShader(mSolidShader);
} else {
if (this.mSolidTintFilter != null) {
solidPaint.setColorFilter(this.mSolidTintFilter);
solidClearColorFilter = true;
} else {
solidClearColorFilter = false;
}
}
for (Path solidPath : mSolidPath) {
canvas.drawPath(solidPath, solidPaint);
}
if (solidClearColorFilter) {
solidPaint.setColorFilter(null);
}
}
}
@Override
public void setAlpha(int alpha) {
if (mBgShader == null) {
this.mBgPaint.setAlpha(alpha);
}
if (mDrawSolid) {
this.mSolidPaint.setAlpha(alpha);
}
}
@Override
public void setColorFilter(ColorFilter cf) {
if (mBgShader == null) {
this.mBgPaint.setColorFilter(cf);
}
if (mDrawSolid) {
this.mSolidPaint.setColorFilter(cf);
}
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
public void setColor(@Nullable ColorStateList backgroundColor, @Nullable ColorStateList solidColorsList) {
this.setBackground(backgroundColor, solidColorsList);
this.invalidateSelf();
}
public ColorStateList getBackGroundColor() {
return this.mBgColorsList;
}
public ColorStateList getSolidColor() {
return this.mSolidColorsList;
}
@Override
public void setTintList(ColorStateList tint) {
if (mBgShader == null) {
this.mBgTint = tint;
this.mBgTintFilter = this.createTintFilter(this.mBgTint, this.mBgTintMode);
}
if (mDrawSolid) {
this.mSolidTint = tint;
this.mSolidTintFilter = this.createTintFilter(this.mSolidTint, this.mSolidTintMode);
}
this.invalidateSelf();
}
@Override
public void setTintMode(PorterDuff.Mode tintMode) {
if (mBgShader == null) {
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);
}
this.invalidateSelf();
}
@Override
protected boolean onStateChange(int[] stateSet) {
boolean bgColorChanged = false;
if (mBgShader == null) {
int newBgColor = this.mBgColorsList.getColorForState(stateSet, this.mBgColorsList.getDefaultColor());
bgColorChanged = newBgColor != this.mBgPaint.getColor();
if (bgColorChanged) {
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();
if (solidColorChanged) {
this.mSolidPaint.setColor(newSolidColor);
}
}
if (this.mBgShader == null && this.mBgTint != null && this.mBgTintMode != null) {
this.mBgTintFilter = this.createTintFilter(this.mBgTint, this.mBgTintMode);
this.invalidateSelf();
return true;
} else if (this.mSolidShader == null && this.mSolidTint != null && this.mSolidTintMode != null) {
this.mSolidTintFilter = this.createTintFilter(this.mSolidTint, this.mSolidTintMode);
return true;
} else {
return bgColorChanged || solidColorChanged;
}
}
@Override
public boolean isStateful() {
if (mDrawSolid) {
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()
|| super.isStateful();
} else {
return this.mBgTint != null && this.mBgTint.isStateful()
|| this.mBgColorsList != null && this.mBgColorsList.isStateful()
|| super.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);
} else {
return null;
}
}
}
4.1创建attrs自定义属性
4.2创建自动适配布局 公共接口IAutoLayout
public interface IAutoLayout {
int AUTO_TYPE_WIDTH = 0;
int AUTO_TYPE_HEIGHT = 1;
@IntDef(value = {AUTO_TYPE_WIDTH, AUTO_TYPE_HEIGHT})
@interface AutoType {
}
/**
* 设置控件宽高信息,并重新布局
*
* @param autoWidth
* @param autoHeight
*/
void setAutoViewInfo(int autoWidth, int autoHeight);
/**
* 设置控件宽高信息,并重新布局
*
* @param autoWidth
* @param autoHeight
*/
void setAutoViewInfo(@AutoType int autoType, int autoWidth, int autoHeight);
}
4.3创建账单适配布局AutoRelativeLayout
public class AutoRelativeLayout extends RelativeLayout implements IAutoLayout {
// 自动适配的类型,0:宽适配 1:高适配
private int auto_type = 1;
private int auto_width;
private int auto_height;
public AutoRelativeLayout(Context context) {
this(context, null);
}
public AutoRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public AutoRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
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);
typedArray.recycle();
}
/**
* @docRoot
*/
@Override
public void setAutoViewInfo(int autoWidth, int autoHeight) {
this.auto_width = autoWidth;
this.auto_height = autoHeight;
requestLayout();
}
/**
* @docRoot
*/
@Override
public void setAutoViewInfo(@AutoType int autoType, int autoWidth, int autoHeight) {
this.auto_type = autoType;
this.auto_width = autoWidth;
this.auto_height = autoHeight;
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (auto_type == -1) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} else {
setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
measureChildren(widthMeasureSpec, heightMeasureSpec);
int viewWidth = getMeasuredWidth();
int viewHeight = getMeasuredHeight();
switch (auto_type) {
case 0: // 动态计算出控件宽
viewWidth = (int) (viewHeight * ((auto_width * 1.0f) / auto_height));
break;
case 1: // 动态计算出控件高
viewHeight = (int) (viewWidth * ((auto_height * 1.0f) / auto_width));
break;
}
widthMeasureSpec = MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
其他AutoLinearLayout,AutoImageView,AutoFrameLayout布局
都是一样的
4.4创建自定义布局适配attrs
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; // 背景渐变颜色值,优先级高于 bgColorStateList
private int bgShaderType; // 渐变类型
private int bgShaderLinearOrientation; // 线性渐变方向
// 边框参数
private int solidWidth;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
// 渐变边框
private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateList
private int solidShaderType; // 边框类型
private int solidShaderLinearOrientation; // 线性渐变方向
// 是否需要强制重新布局
private boolean forceRefreshLayout;
public RadiusRelativeLayout(Context context) {
this(context, null);
}
public RadiusRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RadiusRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public RadiusRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
@Override
protected void init(Context context, AttributeSet attrs) {
super.init(context, attrs);
setWillNotDraw(false);
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;
radiusType.recycle();
// 角度边长不能小于0
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
//如果四个角的值没有设置,那么就使用通用的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);
} else {
dashPathEffect = null;
}
}
@Override
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
forceRefreshLayout();
}
}
@Override
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setRadius(int radius) {
if (radius >= 0) {
leftTopRadius = radius;
rightTopRadius = radius;
rightBottomRadius = radius;
leftBottomRadius = radius;
forceRefreshLayout();
}
}
@Override
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
forceRefreshLayout();
}
@Override
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
forceRefreshLayout();
}
@Override
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 没有发生改变,并且不需要强制刷新就不在重新layout
if (!changed && !this.forceRefreshLayout) {
return;
}
this.forceRefreshLayout = false;
width = getWidth();
height = getHeight();
final Path bgPath = setBackground();
// 手动设置阴影,使用裁剪后的路径,防止阴影直角矩形显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
if (elevation > 0) {
setElevation(elevation);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
if (bgPath.isConvex()) {
outline.setConvexPath(bgPath);
} else {
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
}
}
});
setClipToOutline(true);
}
}
}
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
requestLayout();
}
private Path setBackground() {
Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
Shader bgShader = null;
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
}
// 边框
if (solidWidth > 0) {
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);
} else {
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
}
setBackground(radiusDrawable);
return bgPath;
}
}
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; // 背景渐变颜色值,优先级高于 bgColorStateList
private int bgShaderType; // 渐变类型
private int bgShaderLinearOrientation; // 线性渐变方向
// 边框参数
private int solidWidth;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
// 渐变边框
private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateList
private int solidShaderType; // 边框类型
private int solidShaderLinearOrientation; // 线性渐变方向
// 是否需要强制重新布局
private boolean forceRefreshLayout;
public RadiusLinearLayout(Context context) {
this(context, null, 0);
}
public RadiusLinearLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public RadiusLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public RadiusLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
@Override
protected void init(Context context, AttributeSet attrs) {
super.init(context, attrs);
setWillNotDraw(false);
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;
radiusType.recycle();
// 角度边长不能小于0
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
//如果四个角的值没有设置,那么就使用通用的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);
} else {
dashPathEffect = null;
}
}
@Override
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
forceRefreshLayout();
}
}
@Override
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setRadius(int radius) {
if (radius >= 0) {
leftTopRadius = radius;
rightTopRadius = radius;
rightBottomRadius = radius;
leftBottomRadius = radius;
forceRefreshLayout();
}
}
@Override
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
forceRefreshLayout();
}
@Override
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
forceRefreshLayout();
}
@Override
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 没有发生改变,并且不需要强制刷新就不在重新layout
if (!changed && !this.forceRefreshLayout) {
return;
}
this.forceRefreshLayout = false;
width = getWidth();
height = getHeight();
final Path bgPath = setBackground();
// 手动设置阴影,使用裁剪后的路径,防止阴影直角矩形显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
if (elevation > 0) {
setElevation(elevation);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
if (bgPath.isConvex()) {
outline.setConvexPath(bgPath);
} else {
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
}
}
});
setClipToOutline(true);
}
}
}
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
requestLayout();
}
private Path setBackground() {
Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
Shader bgShader = null;
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
}
// 边框
if (solidWidth > 0) {
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);
} else {
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
}
setBackground(radiusDrawable);
return bgPath;
}
}
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; // 背景渐变颜色值,优先级高于 bgColorStateList
private int bgShaderType; // 渐变类型
private int bgShaderLinearOrientation; // 线性渐变方向
// 边框参数
private int solidWidth;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
// 渐变边框
private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateList
private int solidShaderType; // 边框类型
private int solidShaderLinearOrientation; // 线性渐变方向
// 是否需要强制重新布局
private boolean forceRefreshLayout;
public RadiusTextView(Context context) {
this(context, null);
}
public RadiusTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RadiusTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
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;
radiusType.recycle();
// 角度边长不能小于0
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
//如果四个角的值没有设置,那么就使用通用的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);
} else {
dashPathEffect = null;
}
}
@Override
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
forceRefreshLayout();
}
}
@Override
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setRadius(int radius) {
if (radius >= 0) {
leftTopRadius = radius;
rightTopRadius = radius;
rightBottomRadius = radius;
leftBottomRadius = radius;
forceRefreshLayout();
}
}
@Override
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
forceRefreshLayout();
}
@Override
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
forceRefreshLayout();
}
@Override
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 没有发生改变,并且不需要强制刷新就不在重新layout
if (!changed && !this.forceRefreshLayout) {
return;
}
this.forceRefreshLayout = false;
width = getWidth();
height = getHeight();
final Path bgPath = setBackground();
// 手动设置阴影,使用裁剪后的路径,防止阴影直角矩形显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
if (elevation > 0) {
setElevation(elevation);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
if (bgPath.isConvex()) {
outline.setConvexPath(bgPath);
} else {
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
}
}
});
setClipToOutline(true);
}
}
}
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
requestLayout();
}
private Path setBackground() {
Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
Shader bgShader = null;
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
}
// 边框
if (solidWidth > 0) {
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);
} else {
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
}
setBackground(radiusDrawable);
return bgPath;
}
}
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;
// 3x3 矩阵,主要用于缩小放大
private Matrix matrix;
//渲染图像,使用图像为绘制图形着色
private BitmapShader bitmapShader;
// 边框参数
private int solidWidth;
private int solidColor;
// 是否需要强制重新布局
private boolean forceRefreshLayout;
public RadiusImageView(Context context) {
this(context, null);
}
public RadiusImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RadiusImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@Override
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);
radiusType.recycle();
// 角度边长不能小于0
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
//如果四个角的值没有设置,那么就使用通用的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;
matrix = new Matrix();
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);
} else {
setLineTypeStyle(TYPE_DASH, dashGap, dashWidth, false);
}
}
// 设置线的类型和虚线样式
private void setLineTypeStyle(int lineType, float dashGap, float dashWidth, boolean invalidate) {
if (lineType == TYPE_DASH) {
DashPathEffect dashPathEffect = null;
if (dashWidth > 0) {
dashPathEffect = new DashPathEffect(new float[]{dashWidth, dashGap}, 0);
}
solidPaint.setPathEffect(dashPathEffect);
} else {
solidPaint.setPathEffect(null);
}
if (invalidate) invalidate();
}
public void setSolidColor(int color) {
solidPaint.setColor(color);
forceRefreshLayout();
}
public void setRadius(int radius) {
if (radius >= 0) {
leftTopRadius = radius;
rightTopRadius = radius;
rightBottomRadius = radius;
leftBottomRadius = radius;
forceRefreshLayout();
}
}
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
forceRefreshLayout();
}
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
forceRefreshLayout();
}
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
forceRefreshLayout();
}
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 没有发生改变,并且不需要强制刷新就不在重新layout
if (!changed && !this.forceRefreshLayout) {
return;
}
this.forceRefreshLayout = false;
width = getWidth();
height = getHeight();
// 手动设置阴影,使用裁剪后的路径,防止阴影直角矩形显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
if (elevation > 0) {
setElevation(elevation);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
Path path = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height, false);
outline.setConvexPath(path);
}
});
setClipToOutline(true);
}
}
}
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
requestLayout();
}
@Override
protected void onDraw(Canvas canvas) {
if (leftTopRadius <= DEFAULT_RADIUS && leftBottomRadius <= DEFAULT_RADIUS &&
rightTopRadius <= DEFAULT_RADIUS && rightBottomRadius <= DEFAULT_RADIUS) {
super.onDraw(canvas);
// 边框
if (solidWidth > 0)
canvas.drawPath(RadiusUtils.calculateRectSocketPath(width, height, solidWidth), solidPaint);
} else {
Path path = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, width, height);
Bitmap bitmap = getBitmapFromDrawable(getDrawable());
if (bitmap != null) {
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
configureBounds(getDrawable());
// 设置变换矩阵
bitmapShader.setLocalMatrix(matrix);
// 设置shader
bitmapPaint.setShader(bitmapShader);
canvas.drawPath(path, bitmapPaint);
}
// 边框
if (solidWidth > 0) {
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 == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
try {
Bitmap bitmap;
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLOR_DRAWABLE_DIMENSION, COLOR_DRAWABLE_DIMENSION, BITMAP_CONFIG);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 根据 ScaleType 进行矩阵变换
private void configureBounds(Drawable drawable) {
if (drawable == null) {
return;
}
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) {
matrix = null;
} else {
if (ImageView.ScaleType.MATRIX == scaleType) {
matrix = null;
} else if (fits) {
matrix = null;
} else if (ImageView.ScaleType.CENTER == scaleType) {
if (matrix == null)
matrix = new Matrix();
matrix.setTranslate(Math.round((vWidth - intrinsicWidth) * 0.5f),
Math.round((vHeight - intrinsicHeight) * 0.5f));
} else if (ImageView.ScaleType.CENTER_CROP == scaleType) {
float scale;
float dx = 0, dy = 0;
if (intrinsicWidth * vHeight > vWidth * intrinsicHeight) {
scale = (float) vHeight / (float) intrinsicHeight;
dx = (vWidth - intrinsicWidth * scale) * 0.5f;
} else {
scale = (float) vWidth / (float) intrinsicWidth;
dy = (vHeight - intrinsicHeight * scale) * 0.5f;
}
if (matrix == null)
matrix = new Matrix();
matrix.setScale(scale, scale);
matrix.postTranslate(Math.round(dx), Math.round(dy));
} else if (ImageView.ScaleType.CENTER_INSIDE == scaleType) {
float scale;
float dx;
float dy;
if (intrinsicWidth <= vWidth && intrinsicHeight <= vHeight) {
scale = 1.0f;
} else {
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);
if (matrix == null)
matrix = new Matrix();
matrix.setScale(scale, scale);
matrix.postTranslate(dx, dy);
} else {
RectF mTempSrc = new RectF();
RectF mTempDst = new RectF();
mTempSrc.set(0, 0, intrinsicWidth, intrinsicHeight);
mTempDst.set(0, 0, vWidth, vHeight);
if (matrix == null)
matrix = new Matrix();
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; // 背景渐变颜色值,优先级高于 bgColorStateList
private int bgShaderType; // 渐变类型
private int bgShaderLinearOrientation; // 线性渐变方向
// 边框参数
private int solidWidth;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
// 渐变边框
private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateList
private int solidShaderType; // 边框类型
private int solidShaderLinearOrientation; // 线性渐变方向
// 是否需要强制重新布局
private boolean forceRefreshLayout;
public RadiusFrameLayout(Context context) {
this(context, null);
}
public RadiusFrameLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RadiusFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public RadiusFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
@Override
protected void init(Context context, AttributeSet attrs) {
super.init(context, attrs);
setWillNotDraw(false);
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;
radiusType.recycle();
// 角度边长不能小于0
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
//如果四个角的值没有设置,那么就使用通用的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);
} else {
dashPathEffect = null;
}
}
@Override
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
forceRefreshLayout();
}
}
@Override
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setRadius(int radius) {
if (radius >= 0) {
leftTopRadius = radius;
rightTopRadius = radius;
rightBottomRadius = radius;
leftBottomRadius = radius;
forceRefreshLayout();
}
}
@Override
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
forceRefreshLayout();
}
@Override
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
forceRefreshLayout();
}
@Override
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 没有发生改变,并且不需要强制刷新就不在重新layout
if (!changed && !this.forceRefreshLayout) {
return;
}
this.forceRefreshLayout = false;
width = getWidth();
height = getHeight();
final Path bgPath = setBackground();
// 手动设置阴影,使用裁剪后的路径,防止阴影直角矩形显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
if (elevation > 0) {
setElevation(elevation);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
if (bgPath.isConvex()) {
outline.setConvexPath(bgPath);
} else {
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
}
}
});
setClipToOutline(true);
}
}
}
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
requestLayout();
}
private Path setBackground() {
final Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
Shader bgShader = null;
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
}
// 边框
if (solidWidth > 0) {
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);
} else {
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
}
setBackground(radiusDrawable);
return bgPath;
}
}
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; // 背景渐变颜色值,优先级高于 bgColorStateList
private int bgShaderType; // 渐变类型
private int bgShaderLinearOrientation; // 线性渐变方向
// 边框参数
private int solidWidth;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
// 渐变边框
private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateList
private int solidShaderType; // 边框类型
private int solidShaderLinearOrientation; // 线性渐变方向
// 是否需要强制重新布局
private boolean forceRefreshLayout;
public RadiusEditText(Context context) {
this(context, null);
}
public RadiusEditText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RadiusEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
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;
radiusType.recycle();
// 角度边长不能小于0
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
//如果四个角的值没有设置,那么就使用通用的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);
} else {
dashPathEffect = null;
}
}
@Override
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
forceRefreshLayout();
}
}
@Override
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setRadius(int radius) {
if (radius >= 0) {
leftTopRadius = radius;
rightTopRadius = radius;
rightBottomRadius = radius;
leftBottomRadius = radius;
forceRefreshLayout();
}
}
@Override
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
forceRefreshLayout();
}
@Override
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
forceRefreshLayout();
}
@Override
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 没有发生改变,并且不需要强制刷新就不在重新layout
if (!changed && !this.forceRefreshLayout) {
return;
}
this.forceRefreshLayout = false;
width = getWidth();
height = getHeight();
final Path bgPath = setBackground();
// 手动设置阴影,使用裁剪后的路径,防止阴影直角矩形显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
if (elevation > 0) {
setElevation(elevation);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
if (bgPath.isConvex()) {
outline.setConvexPath(bgPath);
} else {
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
}
}
});
setClipToOutline(true);
}
}
}
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
requestLayout();
}
private Path setBackground() {
Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
Shader bgShader = null;
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
}
// 边框
if (solidWidth > 0) {
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);
} else {
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
}
setBackground(radiusDrawable);
return bgPath;
}
}
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; // 背景渐变颜色值,优先级高于 bgColorStateList
private int bgShaderType; // 渐变类型
private int bgShaderLinearOrientation; // 线性渐变方向
// 边框参数
private int solidWidth;
private ColorStateList solidColorStateList;
private DashPathEffect dashPathEffect = null;
// 渐变边框
private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateList
private int solidShaderType; // 边框类型
private int solidShaderLinearOrientation; // 线性渐变方向
// 是否需要强制重新布局
private boolean forceRefreshLayout;
public RadiusButton(Context context) {
this(context, null);
}
public RadiusButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RadiusButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
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;
radiusType.recycle();
// 角度边长不能小于0
if (DEFAULT_RADIUS >= radius) radius = DEFAULT_RADIUS;
//如果四个角的值没有设置,那么就使用通用的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);
} else {
dashPathEffect = null;
}
}
@Override
public void setBackgroundColor(int color) {
this.bgColorStateList = ColorStateList.valueOf(color);
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setBackgroundColor(ColorStateList bgColorStateList) {
this.bgColorStateList = bgColorStateList;
this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidDashPathEffect(DashPathEffect dashPathEffect) {
if (dashPathEffect != null) {
this.dashPathEffect = dashPathEffect;
forceRefreshLayout();
}
}
@Override
public void setSolidColor(int color) {
this.solidColorStateList = ColorStateList.valueOf(color);
if (radiusDrawable != null) {
radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setSolidColor(ColorStateList solidColorStateList) {
this.solidColorStateList = solidColorStateList;
if (radiusDrawable != null) {
radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);
}
forceRefreshLayout();
}
@Override
public void setRadius(int radius) {
if (radius >= 0) {
leftTopRadius = radius;
rightTopRadius = radius;
rightBottomRadius = radius;
leftBottomRadius = radius;
forceRefreshLayout();
}
}
@Override
public void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {
this.leftTopRadius = leftTopRadius;
this.rightTopRadius = rightTopRadius;
this.rightBottomRadius = rightBottomRadius;
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftTopRadius(int leftTopRadius) {
this.leftTopRadius = leftTopRadius;
forceRefreshLayout();
}
@Override
public void setRightTopRadius(int rightTopRadius) {
this.rightTopRadius = rightTopRadius;
forceRefreshLayout();
}
@Override
public void setRightBottomRadius(int rightBottomRadius) {
this.rightBottomRadius = rightBottomRadius;
forceRefreshLayout();
}
@Override
public void setLeftBottomRadius(int leftBottomRadius) {
this.leftBottomRadius = leftBottomRadius;
forceRefreshLayout();
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.bgShaderType = shapeType;
this.bgShaderColors = shapeColors;
this.bgShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {
setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);
}
@Override
public void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors, @ShaderUtils.LinearOrientation int shaderLinearOrientation) {
if (shapeColors == null || shapeColors.length <= 0)
return;
this.solidShaderType = shapeType;
this.solidShaderColors = shapeColors;
this.solidShaderLinearOrientation = shaderLinearOrientation;
forceRefreshLayout();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 没有发生改变,并且不需要强制刷新就不在重新layout
if (!changed && !this.forceRefreshLayout) {
return;
}
this.forceRefreshLayout = false;
width = getWidth();
height = getHeight();
final Path bgPath = setBackground();
// 手动设置阴影,使用裁剪后的路径,防止阴影直角矩形显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float elevation = Math.max(getElevation(), getTranslationZ());
if (elevation > 0) {
setElevation(elevation);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
if (bgPath.isConvex()) {
outline.setConvexPath(bgPath);
} else {
outline.setConvexPath(RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height, false));
}
}
});
setClipToOutline(true);
}
}
}
private void forceRefreshLayout() {
this.forceRefreshLayout = true;
requestLayout();
}
private Path setBackground() {
Path bgPath = RadiusUtils.calculateBgPath(leftTopRadius, rightTopRadius,
leftBottomRadius, rightBottomRadius, width, height);
Shader bgShader = null;
if (bgShaderType != ShaderUtils.SHADER_TYPE_NONE) {
bgShader = ShaderUtils.createShader(bgShaderType, width, height, bgShaderColors, bgShaderLinearOrientation);
}
// 边框
if (solidWidth > 0) {
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);
} else {
radiusDrawable = new RadiusDrawable(bgColorStateList, bgShader, bgPath);
}
setBackground(radiusDrawable);
return bgPath;
}
}
12.代码使用样式