注册

含有边框的TextView-Android

前言

实际的项目中我们经常会遇到边框的问题,一开始我都是直接用shape来实现,但是这种方式非常的麻烦,后面又用了三方库SuperTextView,后面学习了自定义View自己来实现一下吧.

Code

public class BorderTextView extends AppCompatTextView {

public BorderTextView(Context context) {
this(context, null);
}

public BorderTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public BorderTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}


/**
* @param borderColor border颜色
* @param borderWidths border 宽度
* @param borderRadius border 圆角半径
*/
public void setBorder(final int borderColor, final int[] borderWidths, final int[] borderRadius) {
setTextColor(borderColor);
Drawable drawable = new GradientDrawable() {
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
drawBorder(canvas, borderColor, borderWidths, borderRadius);
}
};
setBackground(drawable);
}

/**
* 绘制border
*/
private void drawBorder(Canvas canvas, final int borderColor, final int[] borderWidths, final int[] borderRadius) {
//获取当前canvas的宽高
Rect rect = canvas.getClipBounds();
final int width = rect.width();
final int height = rect.height();

int borderWidthLeft;
int borderWidthTop;
int borderWidthRight;
int borderWidthBottom;

//取得我们的边框宽度,并附加给相应变量
if (borderWidths != null && borderWidths.length == 4) {
borderWidthLeft = Math.min(width / 2, borderWidths[0]);
borderWidthTop = Math.min(height / 2, borderWidths[1]);
borderWidthRight = Math.min(width / 2, borderWidths[2]);
borderWidthBottom = Math.min(height / 2, borderWidths[3]);
} else {
return;
}

// 设置画笔
Paint paint = new Paint();
//抗锯齿
paint.setAntiAlias(true);
//画笔颜色
paint.setColor(borderColor);
//画笔样式
paint.setStyle(Paint.Style.STROKE);
//设置边框宽度
paint.setStrokeWidth(borderWidthLeft);

// 判断当前边框是否相等
if ((borderWidthLeft == borderWidthTop) && (borderWidthLeft == borderWidthRight) && (borderWidthLeft == borderWidthBottom)) {
if (borderWidthLeft == 0) {
return;
}
// borderRadius != null且borderWidth!-0;计算并画出圆角边框,否则为直角边框
if (borderRadius != null && borderRadius.length == 4) {
int sum = 0;
/**
* 循环传递的最后一个参数,相加
* 是数组的原因是适应更多的边框需求,因为你不一定四个边框都是一个圆角度数
*/
for (int i = 0; i < borderRadius.length; i++) {
if (borderRadius[i] < 0) {
return;
}
sum += borderRadius[i];
}
//如果传递的都是0直接绘制即可
if (sum == 0) {
canvas.drawRect(rect, paint);
}
int borderWidth = borderWidthLeft;

int mMaxRadiusX = width / 2 - borderWidth / 2;
int mMaxRadiusY = height / 2 - borderWidth / 2;

int topLeftRadiusX = Math.min(mMaxRadiusX, borderRadius[0]);
int topLeftRadiusY = Math.min(mMaxRadiusY, borderRadius[0]);
int topRightRadiusX = Math.min(mMaxRadiusX, borderRadius[1]);
int topRightRadiusY = Math.min(mMaxRadiusY, borderRadius[1]);
int bottomRightRadiusX = Math.min(mMaxRadiusX, borderRadius[2]);
int bottomRightRadiusY = Math.min(mMaxRadiusY, borderRadius[2]);
int bottomLeftRadiusX = Math.min(mMaxRadiusX, borderRadius[3]);
int bottomLeftRadiusY = Math.min(mMaxRadiusY, borderRadius[3]);

//绘制左上圆角,通过旋转来达到圆角的效果,本质上其实绘制的是圆弧
if (topLeftRadiusX < borderWidth || topLeftRadiusY < borderWidth) {

RectF arc1 = new RectF(0, 0, topLeftRadiusX * 2, topLeftRadiusY * 2);
paint.setStyle(Paint.Style.FILL);
canvas.drawArc(arc1, 180, 90, true, paint);
} else {
RectF arc1 = new RectF(borderWidth / 2, borderWidth / 2, topLeftRadiusX * 2 - borderWidth / 2, topLeftRadiusY * 2 - borderWidth / 2);
paint.setStyle(Paint.Style.STROKE);
canvas.drawArc(arc1, 180, 90, false, paint);
}
//绘制上方的边框
canvas.drawLine(topLeftRadiusX, borderWidth / 2, width - topRightRadiusX, borderWidth / 2, paint);

//绘制右上圆角
if (topRightRadiusX < borderWidth || topRightRadiusY < borderWidth) {
RectF arc2 = new RectF(width - topRightRadiusX * 2, 0, width, topRightRadiusY * 2);
paint.setStyle(Paint.Style.FILL);
canvas.drawArc(arc2, 270, 90, true, paint);
} else {
RectF arc2 = new RectF(width - topRightRadiusX * 2 + borderWidth / 2, borderWidth / 2, width - borderWidth / 2, topRightRadiusY * 2 - borderWidth / 2);
paint.setStyle(Paint.Style.STROKE);
canvas.drawArc(arc2, 270, 90, false, paint);
}
//绘制右边边框
canvas.drawLine(width - borderWidth / 2, topRightRadiusY, width - borderWidth / 2, height - bottomRightRadiusY, paint);
//绘制右下圆角
if (bottomRightRadiusX < borderWidth || bottomRightRadiusY < borderWidth) {
RectF arc3 = new RectF(width - bottomRightRadiusX * 2, height - bottomRightRadiusY * 2, width, height);
paint.setStyle(Paint.Style.FILL);
canvas.drawArc(arc3, 0, 90, true, paint);
} else {
RectF arc3 = new RectF(width - bottomRightRadiusX * 2 + borderWidth / 2, height - bottomRightRadiusY * 2 + borderWidth / 2, width - borderWidth / 2, height - borderWidth / 2);
paint.setStyle(Paint.Style.STROKE);
canvas.drawArc(arc3, 0, 90, false, paint);
}
//绘制底部边框
canvas.drawLine(bottomLeftRadiusX, height - borderWidth / 2, width - bottomRightRadiusX, height - borderWidth / 2, paint);
//绘制左下圆角
if (bottomLeftRadiusX < borderWidth || bottomLeftRadiusY < borderWidth) {
RectF arc4 = new RectF(0, height - bottomLeftRadiusY * 2, bottomLeftRadiusX * 2, height);
paint.setStyle(Paint.Style.FILL);
canvas.drawArc(arc4, 90, 90, true, paint);
} else {
RectF arc4 = new RectF(borderWidth / 2, height - bottomLeftRadiusY * 2 + borderWidth / 2, bottomLeftRadiusX * 2 - borderWidth / 2, height - borderWidth / 2);
paint.setStyle(Paint.Style.STROKE);
canvas.drawArc(arc4, 90, 90, false, paint);
}
//绘制左边边框
canvas.drawLine(borderWidth / 2, topLeftRadiusY, borderWidth / 2, height - bottomLeftRadiusY, paint);
} else {
//如果没有传递圆角的参数,直接绘制即可
canvas.drawRect(rect, paint);
}
} else {
//当边框的宽度不同时,绘制不同的线粗,通过borderWidthLeft,rect.top,rect.bottom来确定每根线所在的位置
if (borderWidthLeft > 0) {
paint.setStrokeWidth(borderWidthLeft);
canvas.drawLine(borderWidthLeft / 2, rect.top, borderWidthLeft / 2, rect.bottom, paint);
}
if (borderWidthTop > 0) {
paint.setStrokeWidth(borderWidthTop);
canvas.drawLine(rect.left, borderWidthTop / 2, rect.right, borderWidthTop / 2, paint);
}
if (borderWidthRight > 0) {
paint.setStrokeWidth(borderWidthRight);
canvas.drawLine(rect.right - borderWidthRight / 2, rect.top, rect.right - borderWidthRight / 2, rect.bottom, paint);
}
if (borderWidthBottom > 0) {
paint.setStrokeWidth(borderWidthBottom);
canvas.drawLine(rect.left, rect.bottom - borderWidthBottom / 2, width, rect.bottom - borderWidthBottom / 2, paint);
}
}
}
}

效果

image.png

相应代码里都有注释,代码本质是通过绘制四根线来实现边框的效果,通过我们传递的两个参数,一个是边框宽度,利用数组,拥有更强的扩展性,可以设置四个方向的线粗.第二个是圆角度数,顺序分别是左上,右上,右下,左下.

当我们的圆角有参数时,线的宽度是有改变的,会稍微短一点,留给矩形控件,防止过度绘制.

Drawable drawable = new GradientDrawable() {
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
drawBorder(canvas, borderColor, borderWidths, borderRadius);
}
};

这一部分代码你也可以使用BitmapDrawable,不过编译器会提示过时,问题不大,也能运行.

这种代码我不知道该怎么解释,相应的RectF,canvas的构造方法我都介绍吐了,都是一个样子,只不过计算宽高很复杂而已,总之思路就向上面说的一样.

0 个评论

要回复文章请先登录注册