1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Android实现自定义圆角边框渐变

Android实现自定义圆角边框渐变

时间:2021-01-30 18:16:47

相关推荐

Android实现自定义圆角边框渐变

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<Integer> 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<Integer> 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<br/>* <b>ConvexPath 这里简单理解:圆角矩形的圆角度数大于矩形的高度或宽度(上下圆角度数的边长和大于高度或者左右圆角度数的边长大于高度,那么就不是 ConvexPath 了)</b>** @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<br/>* <b>ConvexPath 这里简单理解:圆角矩形的圆角度数大于矩形的高度或宽度(上下圆角度数的边长和大于高度或者左右圆角度数的边长大于高度,那么就不是 ConvexPath 了)</b>** @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<br/>* <b>ConvexPath 这里简单理解:圆角矩形的圆角度数大于矩形的高度或宽度(上下圆角度数的边长和大于高度或者左右圆角度数的边长大于高度,那么就不是 ConvexPath 了)</b>** @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;}/*** 根据同边的两个圆角的分别长度和边的长度,重新计算两个圆角该有的长度(防止两个圆角的同边长度之后大于总的长度)<br/>* 如:给出左上角上边的长度和右上角上边的长度,以及矩形的上边边长(矩形的长),重新计算出左上角上边的长度和右上角上边的长度,* 防止左上角上边的长度和右上角上边的长度之和大于边长导致出错,如果大于边长时,根据比例计算。** @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<Path> 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<Path> 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<Path>() : 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()));}}@Overridepublic 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);}}}@Overridepublic void setAlpha(int alpha) {if (mBgShader == null) {this.mBgPaint.setAlpha(alpha);}if (mDrawSolid) {this.mSolidPaint.setAlpha(alpha);}}@Overridepublic void setColorFilter(ColorFilter cf) {if (mBgShader == null) {this.mBgPaint.setColorFilter(cf);}if (mDrawSolid) {this.mSolidPaint.setColorFilter(cf);}}@Overridepublic 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;}@Overridepublic 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();}@Overridepublic 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();}@Overrideprotected 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;}}@Overridepublic 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自定义属性

<!--圆角控件属性--><declare-styleable name="RadiusView"><!--圆角属性--><attr name="rv_radius_all" format="dimension" /><attr name="rv_radius_leftTop" format="dimension" /><attr name="rv_radius_rightTop" format="dimension" /><attr name="rv_radius_rightBottom" format="dimension" /><attr name="rv_radius_leftBottom" format="dimension" /><!--背景颜色,系统的background将会失效,和 rv_shader_xxx 属性为互斥,rv_shader_xxx 优先级更高--><attr name="rv_background_color" format="color" /><!--背景颜色,使用渐变,系统的background将会失效,和 rv_background_color 属性为互斥,rv_shader_xxx 优先级更高--><attr name="rv_shader_start_color" format="color" /><attr name="rv_shader_middle_color" format="color" /><attr name="rv_shader_middle_color2" format="color" /><attr name="rv_shader_middle_color3" format="color" /><attr name="rv_shader_end_color" format="color" /><!--背景颜色,使用渐变,渐变类型(如果使用渐变,此为必须设置属性,否则不是使用渐变)。系统的background将会失效--><attr name="rv_shader_type" format="enum"><enum name="linear" value="10" /><enum name="radial" value="11" /><enum name="sweep" value="12" /></attr><!--背景颜色,使用渐变,线性渐变特有属性,渐变方向。系统的background将会失效--><attr name="rv_shader_linear_orientation" format="enum"><enum name="top_to_bottom" value="110" /><enum name="bottom_to_top" value="111" /><enum name="left_to_right" value="220" /><enum name="right_to_left" value="221" /><enum name="leftTop_to_rightBottom" value="330" /><enum name="rightBottom_to_leftTop" value="331" /><enum name="rightTop_to_leftBottom" value="440" /><enum name="leftBottom_to_rightTop" value="441" /></attr><!--边框属性--><attr name="rv_solid_width" format="dimension" /><attr name="rv_solid_color" format="color" /><!--虚线长度--><attr name="rv_solid_dashWidth" format="dimension" /><!--线间隔--><attr name="rv_solid_dashGap" format="dimension" /><!--线类型 实线/虚线--><attr name="rv_solid_type" format="enum"><!--水平线--><enum name="solid" value="0" /><!--垂直线--><enum name="dash" value="1" /></attr><!--边框颜色,使用渐变,系统的background将会失效,和 rv_background_color 属性为互斥,rv_shader_xxx 优先级更高--><attr name="rv_solid_shader_start_color" format="color" /><attr name="rv_solid_shader_middle_color" format="color" /><attr name="rv_solid_shader_middle_color2" format="color" /><attr name="rv_solid_shader_middle_color3" format="color" /><attr name="rv_solid_shader_end_color" format="color" /><!--边框颜色,使用渐变,渐变类型(如果使用渐变,此为必须设置属性,否则不是使用渐变)。系统的background将会失效--><attr name="rv_solid_shader_type" format="enum"><enum name="linear" value="10" /><enum name="radial" value="11" /><enum name="sweep" value="12" /></attr><!--边框颜色,使用渐变,线性渐变特有属性,渐变方向。系统的background将会失效--><attr name="rv_solid_shader_linear_orientation" format="enum"><enum name="top_to_bottom" value="110" /><enum name="bottom_to_top" value="111" /><enum name="left_to_right" value="220" /><enum name="right_to_left" value="221" /><enum name="leftTop_to_rightBottom" value="330" /><enum name="rightBottom_to_leftTop" value="331" /><enum name="rightTop_to_leftBottom" value="440" /><enum name="leftBottom_to_rightTop" value="441" /></attr></declare-styleable>

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*/@Overridepublic void setAutoViewInfo(int autoWidth, int autoHeight) {this.auto_width = autoWidth;this.auto_height = autoHeight;requestLayout();}/*** @docRoot*/@Overridepublic void setAutoViewInfo(@AutoType int autoType, int autoWidth, int autoHeight) {this.auto_type = autoType;this.auto_width = autoWidth;this.auto_height = autoHeight;requestLayout();}@Overrideprotected 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

<!--通过宽高比例自动适配的控件属性--><declare-styleable name="AutoWidthHeightView"><attr name="auto_view_width" format="integer" /><attr name="auto_view_height" format="integer" /><attr name="auto_view_type" format="enum"><enum name="auto_view_width" value="0" /><enum name="auto_view_height" value="1" /></attr></declare-styleable>

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; // 背景渐变颜色值,优先级高于 bgColorStateListprivate int bgShaderType; // 渐变类型private int bgShaderLinearOrientation; // 线性渐变方向// 边框参数private int solidWidth;private ColorStateList solidColorStateList;private DashPathEffect dashPathEffect = null;// 渐变边框private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateListprivate 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);}@Overrideprotected 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();// 角度边长不能小于0if (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;}}@Overridepublic void setBackgroundColor(int color) {this.bgColorStateList = ColorStateList.valueOf(color);this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setBackgroundColor(ColorStateList bgColorStateList) {this.bgColorStateList = bgColorStateList;this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidDashPathEffect(DashPathEffect dashPathEffect) {if (dashPathEffect != null) {this.dashPathEffect = dashPathEffect;forceRefreshLayout();}}@Overridepublic void setSolidColor(int color) {this.solidColorStateList = ColorStateList.valueOf(color);if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidColor(ColorStateList solidColorStateList) {this.solidColorStateList = solidColorStateList;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);}forceRefreshLayout();}@Overridepublic void setRadius(int radius) {if (radius >= 0) {leftTopRadius = radius;rightTopRadius = radius;rightBottomRadius = radius;leftBottomRadius = radius;forceRefreshLayout();}}@Overridepublic void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {this.leftTopRadius = leftTopRadius;this.rightTopRadius = rightTopRadius;this.rightBottomRadius = rightBottomRadius;this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftTopRadius(int leftTopRadius) {this.leftTopRadius = leftTopRadius;forceRefreshLayout();}@Overridepublic void setRightTopRadius(int rightTopRadius) {this.rightTopRadius = rightTopRadius;forceRefreshLayout();}@Overridepublic void setRightBottomRadius(int rightBottomRadius) {this.rightBottomRadius = rightBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftBottomRadius(int leftBottomRadius) {this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overridepublic void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);// 没有发生改变,并且不需要强制刷新就不在重新layoutif (!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() {@Overridepublic 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<Path> 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; // 背景渐变颜色值,优先级高于 bgColorStateListprivate int bgShaderType; // 渐变类型private int bgShaderLinearOrientation; // 线性渐变方向// 边框参数private int solidWidth;private ColorStateList solidColorStateList;private DashPathEffect dashPathEffect = null;// 渐变边框private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateListprivate 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);}@Overrideprotected 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();// 角度边长不能小于0if (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;}}@Overridepublic void setBackgroundColor(int color) {this.bgColorStateList = ColorStateList.valueOf(color);this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setBackgroundColor(ColorStateList bgColorStateList) {this.bgColorStateList = bgColorStateList;this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidDashPathEffect(DashPathEffect dashPathEffect) {if (dashPathEffect != null) {this.dashPathEffect = dashPathEffect;forceRefreshLayout();}}@Overridepublic void setSolidColor(int color) {this.solidColorStateList = ColorStateList.valueOf(color);if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidColor(ColorStateList solidColorStateList) {this.solidColorStateList = solidColorStateList;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);}forceRefreshLayout();}@Overridepublic void setRadius(int radius) {if (radius >= 0) {leftTopRadius = radius;rightTopRadius = radius;rightBottomRadius = radius;leftBottomRadius = radius;forceRefreshLayout();}}@Overridepublic void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {this.leftTopRadius = leftTopRadius;this.rightTopRadius = rightTopRadius;this.rightBottomRadius = rightBottomRadius;this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftTopRadius(int leftTopRadius) {this.leftTopRadius = leftTopRadius;forceRefreshLayout();}@Overridepublic void setRightTopRadius(int rightTopRadius) {this.rightTopRadius = rightTopRadius;forceRefreshLayout();}@Overridepublic void setRightBottomRadius(int rightBottomRadius) {this.rightBottomRadius = rightBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftBottomRadius(int leftBottomRadius) {this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overridepublic void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);// 没有发生改变,并且不需要强制刷新就不在重新layoutif (!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() {@Overridepublic 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<Path> 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; // 背景渐变颜色值,优先级高于 bgColorStateListprivate int bgShaderType; // 渐变类型private int bgShaderLinearOrientation; // 线性渐变方向// 边框参数private int solidWidth;private ColorStateList solidColorStateList;private DashPathEffect dashPathEffect = null;// 渐变边框private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateListprivate 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();// 角度边长不能小于0if (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;}}@Overridepublic void setBackgroundColor(int color) {this.bgColorStateList = ColorStateList.valueOf(color);this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setBackgroundColor(ColorStateList bgColorStateList) {this.bgColorStateList = bgColorStateList;this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidDashPathEffect(DashPathEffect dashPathEffect) {if (dashPathEffect != null) {this.dashPathEffect = dashPathEffect;forceRefreshLayout();}}@Overridepublic void setSolidColor(int color) {this.solidColorStateList = ColorStateList.valueOf(color);if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidColor(ColorStateList solidColorStateList) {this.solidColorStateList = solidColorStateList;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);}forceRefreshLayout();}@Overridepublic void setRadius(int radius) {if (radius >= 0) {leftTopRadius = radius;rightTopRadius = radius;rightBottomRadius = radius;leftBottomRadius = radius;forceRefreshLayout();}}@Overridepublic void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {this.leftTopRadius = leftTopRadius;this.rightTopRadius = rightTopRadius;this.rightBottomRadius = rightBottomRadius;this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftTopRadius(int leftTopRadius) {this.leftTopRadius = leftTopRadius;forceRefreshLayout();}@Overridepublic void setRightTopRadius(int rightTopRadius) {this.rightTopRadius = rightTopRadius;forceRefreshLayout();}@Overridepublic void setRightBottomRadius(int rightBottomRadius) {this.rightBottomRadius = rightBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftBottomRadius(int leftBottomRadius) {this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overridepublic void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);// 没有发生改变,并且不需要强制刷新就不在重新layoutif (!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() {@Overridepublic 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<Path> 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.圆角ImageRadiusImageView

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);}@Overrideprotected 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();// 角度边长不能小于0if (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();}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);// 没有发生改变,并且不需要强制刷新就不在重新layoutif (!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() {@Overridepublic 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();}@Overrideprotected 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);// 设置shaderbitmapPaint.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; // 背景渐变颜色值,优先级高于 bgColorStateListprivate int bgShaderType; // 渐变类型private int bgShaderLinearOrientation; // 线性渐变方向// 边框参数private int solidWidth;private ColorStateList solidColorStateList;private DashPathEffect dashPathEffect = null;// 渐变边框private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateListprivate 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);}@Overrideprotected 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();// 角度边长不能小于0if (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;}}@Overridepublic void setBackgroundColor(int color) {this.bgColorStateList = ColorStateList.valueOf(color);this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setBackgroundColor(ColorStateList bgColorStateList) {this.bgColorStateList = bgColorStateList;this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidDashPathEffect(DashPathEffect dashPathEffect) {if (dashPathEffect != null) {this.dashPathEffect = dashPathEffect;forceRefreshLayout();}}@Overridepublic void setSolidColor(int color) {this.solidColorStateList = ColorStateList.valueOf(color);if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidColor(ColorStateList solidColorStateList) {this.solidColorStateList = solidColorStateList;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);}forceRefreshLayout();}@Overridepublic void setRadius(int radius) {if (radius >= 0) {leftTopRadius = radius;rightTopRadius = radius;rightBottomRadius = radius;leftBottomRadius = radius;forceRefreshLayout();}}@Overridepublic void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {this.leftTopRadius = leftTopRadius;this.rightTopRadius = rightTopRadius;this.rightBottomRadius = rightBottomRadius;this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftTopRadius(int leftTopRadius) {this.leftTopRadius = leftTopRadius;forceRefreshLayout();}@Overridepublic void setRightTopRadius(int rightTopRadius) {this.rightTopRadius = rightTopRadius;forceRefreshLayout();}@Overridepublic void setRightBottomRadius(int rightBottomRadius) {this.rightBottomRadius = rightBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftBottomRadius(int leftBottomRadius) {this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overridepublic void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);// 没有发生改变,并且不需要强制刷新就不在重新layoutif (!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() {@Overridepublic 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<Path> 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; // 背景渐变颜色值,优先级高于 bgColorStateListprivate int bgShaderType; // 渐变类型private int bgShaderLinearOrientation; // 线性渐变方向// 边框参数private int solidWidth;private ColorStateList solidColorStateList;private DashPathEffect dashPathEffect = null;// 渐变边框private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateListprivate 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();// 角度边长不能小于0if (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;}}@Overridepublic void setBackgroundColor(int color) {this.bgColorStateList = ColorStateList.valueOf(color);this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setBackgroundColor(ColorStateList bgColorStateList) {this.bgColorStateList = bgColorStateList;this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidDashPathEffect(DashPathEffect dashPathEffect) {if (dashPathEffect != null) {this.dashPathEffect = dashPathEffect;forceRefreshLayout();}}@Overridepublic void setSolidColor(int color) {this.solidColorStateList = ColorStateList.valueOf(color);if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidColor(ColorStateList solidColorStateList) {this.solidColorStateList = solidColorStateList;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);}forceRefreshLayout();}@Overridepublic void setRadius(int radius) {if (radius >= 0) {leftTopRadius = radius;rightTopRadius = radius;rightBottomRadius = radius;leftBottomRadius = radius;forceRefreshLayout();}}@Overridepublic void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {this.leftTopRadius = leftTopRadius;this.rightTopRadius = rightTopRadius;this.rightBottomRadius = rightBottomRadius;this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftTopRadius(int leftTopRadius) {this.leftTopRadius = leftTopRadius;forceRefreshLayout();}@Overridepublic void setRightTopRadius(int rightTopRadius) {this.rightTopRadius = rightTopRadius;forceRefreshLayout();}@Overridepublic void setRightBottomRadius(int rightBottomRadius) {this.rightBottomRadius = rightBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftBottomRadius(int leftBottomRadius) {this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overridepublic void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);// 没有发生改变,并且不需要强制刷新就不在重新layoutif (!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() {@Overridepublic 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<Path> 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.圆角ButtonRadiusButton

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; // 背景渐变颜色值,优先级高于 bgColorStateListprivate int bgShaderType; // 渐变类型private int bgShaderLinearOrientation; // 线性渐变方向// 边框参数private int solidWidth;private ColorStateList solidColorStateList;private DashPathEffect dashPathEffect = null;// 渐变边框private int[] solidShaderColors; // 边框渐变颜色值,优先级高于 bgColorStateListprivate 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();// 角度边长不能小于0if (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;}}@Overridepublic void setBackgroundColor(int color) {this.bgColorStateList = ColorStateList.valueOf(color);this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setBackgroundColor(ColorStateList bgColorStateList) {this.bgColorStateList = bgColorStateList;this.bgShaderType = ShaderUtils.SHADER_TYPE_NONE;if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidDashPathEffect(DashPathEffect dashPathEffect) {if (dashPathEffect != null) {this.dashPathEffect = dashPathEffect;forceRefreshLayout();}}@Overridepublic void setSolidColor(int color) {this.solidColorStateList = ColorStateList.valueOf(color);if (radiusDrawable != null) {radiusDrawable.setBackground(this.bgColorStateList, solidColorStateList);}forceRefreshLayout();}@Overridepublic void setSolidColor(ColorStateList solidColorStateList) {this.solidColorStateList = solidColorStateList;if (radiusDrawable != null) {radiusDrawable.setBackground(bgColorStateList, this.solidColorStateList);}forceRefreshLayout();}@Overridepublic void setRadius(int radius) {if (radius >= 0) {leftTopRadius = radius;rightTopRadius = radius;rightBottomRadius = radius;leftBottomRadius = radius;forceRefreshLayout();}}@Overridepublic void setRadius(int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) {this.leftTopRadius = leftTopRadius;this.rightTopRadius = rightTopRadius;this.rightBottomRadius = rightBottomRadius;this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftTopRadius(int leftTopRadius) {this.leftTopRadius = leftTopRadius;forceRefreshLayout();}@Overridepublic void setRightTopRadius(int rightTopRadius) {this.rightTopRadius = rightTopRadius;forceRefreshLayout();}@Overridepublic void setRightBottomRadius(int rightBottomRadius) {this.rightBottomRadius = rightBottomRadius;forceRefreshLayout();}@Overridepublic void setLeftBottomRadius(int leftBottomRadius) {this.leftBottomRadius = leftBottomRadius;forceRefreshLayout();}@Overridepublic void setShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overridepublic void setSolidShaderInfo(@ShaderUtils.ShaderType int shapeType, int[] shapeColors) {setSolidShaderInfo(shapeType, shapeColors, ShaderUtils.LINEAR_ORIENTATION_TOP_TO_BOTTOM);}@Overridepublic 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();}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);// 没有发生改变,并且不需要强制刷新就不在重新layoutif (!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() {@Overridepublic 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<Path> 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.代码使用样式

<com.sc.scxm.cs.radius.RadiusRelativeLayoutandroid:layout_centerInParent="true"android:layout_width="@dimen/dp_100"android:layout_height="@dimen/dp_100"app:rv_radius_all="@dimen/dp_10"app:rv_background_color="@color/colorAccent"app:rv_solid_width="@dimen/dp_1"app:rv_solid_shader_start_color="#CDBC78"app:rv_solid_shader_middle_color="#F5FFE3"app:rv_solid_shader_middle_color2="#CCBA77"app:rv_solid_shader_middle_color3="@color/white"app:rv_solid_shader_end_color="#DDC66D"app:rv_solid_shader_type="linear"/>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。