一,背景
写Android也有些年头了,今年也打算把自己绘制过的自定义View从简单到复杂做一个整合,温故而知新,也希望能给从事Android开发的弟兄们一个参考,喜欢就多多支持,入下图,本文主要讲解如何绘制一个圆角矩形的指示器。

二,绘制流程
- 首先,回忆一下我们自定义View必走的三部曲,测量宽高(onMeasure),布置布局(onLayout),绘制内容(onDraw),无论我们绘制多炫酷复杂效果的View都离不开这三个步骤
- 那么回到主题,我们首先要初始化两支画笔,一支用于绘制被选中的tab(紫色),一直用于绘制未被选中的tab(白色),并将画笔的样式设置为填充内部

ini
mUnSelectedPaint = new Paint();
mUnSelectedPaint.setColor(mUnSelectedColor);
mUnSelectedPaint.setStyle(Paint.Style.FILL);
mUnSelectedPaint.setStrokeWidth(10f);
mSelectedPaint = new Paint();
mSelectedPaint.setColor(mSelectedColor);
mSelectedPaint.setStyle(Paint.Style.FILL);
mSelectedPaint.setStrokeWidth(10f);
- 测量宽高,这里我没有把宽高写死也没有自定义宽高的逻辑,所以直接走Android默认的测量逻辑,仅仅记录View的宽度,稍后用于计算每个tab的宽度
java
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = MeasureSpec.getSize(widthMeasureSpec);
}
-
因为我们是自定义View而并非是ViewGroup,所以没有子View需要布置(所谓布置就是将子View进行摆放),就没有onLayout这个步骤(onLayout是ViewGroup的方法)
-
绘制圆角矩形,先通过View的总宽度减去每个tab之间的边距,就能得到可用的总宽度,可用总宽度除以tab的个数,就能得到每个tab的宽度,循环遍历绘制所有的tab,left进行累加,就能计算出每个tab开始的x坐标,y坐标=left+width,然后根据左右,上下的坐标绘制一个个圆角矩形
ini
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
//计算每个item的大小
float useWidth = mWidth - (mHorizontalSpace * (mCount - 1));
float width = useWidth / mCount;
//绘制圆角矩形
float left = 0;
for (int i = 0; i < mCount; i++) {
RectF rect = new RectF(left, 0, left + width, mHeight);
left = rect.right + mHorizontalSpace;
canvas.drawRoundRect(rect, mRound, mRound, mCurrentCount >= i ? mSelectedPaint : mUnSelectedPaint);
}
}
- 完整代码
java
/**
* create by lijianhui
* on 2022-7-7
* <p>
* description: 引导进度条
*/
public class GuideProgressView extends View {
private final Paint mUnSelectedPaint;
private final Paint mSelectedPaint;
private float mWidth;
private float mHeight = DensityUtil.dp2px(5);
private float mHorizontalSpace = DensityUtil.dp2px(6);
private float mRound = DensityUtil.dp2px(3);
private int mCount = 4;
private int mCurrentCount = 0;
private int mSelectedColor = Color.parseColor("#A599FF");
private int mUnSelectedColor = Color.WHITE;
public GuideProgressView(Context context) {
this(context, null);
}
public GuideProgressView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public GuideProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mUnSelectedPaint = new Paint();
mUnSelectedPaint.setColor(mUnSelectedColor);
mUnSelectedPaint.setStyle(Paint.Style.FILL);
mUnSelectedPaint.setStrokeWidth(10f);
mSelectedPaint = new Paint();
mSelectedPaint.setColor(mSelectedColor);
mSelectedPaint.setStyle(Paint.Style.FILL);
mSelectedPaint.setStrokeWidth(10f);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = MeasureSpec.getSize(widthMeasureSpec);
}
/**
* 绘制
*
* @param canvas 画布
*/
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
//计算每个item的大小
float useWidth = mWidth - (mHorizontalSpace * (mCount - 1));
float width = useWidth / mCount;
//绘制圆角矩形
float left = 0;
for (int i = 0; i < mCount; i++) {
RectF rect = new RectF(left, 0, left + width, mHeight);
left = rect.right + mHorizontalSpace;
canvas.drawRoundRect(rect, mRound, mRound, mCurrentCount >= i ? mSelectedPaint : mUnSelectedPaint);
}
}
/**
* 设置高度
*
* @param height 高度
*/
public void setGuideItemHeight(float height) {
this.mHeight = height;
}
/**
* 设置水平间距
*
* @param horizontalSpace 水平间距
*/
public void setHorizontalSpace(float horizontalSpace) {
this.mHorizontalSpace = horizontalSpace;
}
/**
* 设置圆角
*
* @param round 圆角大小
*/
public void setGuideItemRound(float round) {
this.mRound = round;
}
/**
* 设置个数
*
* @param count 个数
*/
public void setGuideItemCount(int count) {
this.mCount = count;
invalidate();
}
/**
* 选中下一个
*/
public void selectedNext() {
mCurrentCount++;
invalidate();
}
/**
* 获取当前步骤
*
* @return 步骤数
*/
public int getCurrentPos() {
return mCurrentCount;
}
/**
* 设置选中的颜色
*
* @param selectedColor 颜色
*/
public void setSelectedGuideItemColor(int selectedColor) {
this.mSelectedColor = selectedColor;
}
/**
* 设置未选中的颜色
*
* @param unSelectedColor 颜色
*/
public void setUnSelectedGuideItemColor(int unSelectedColor) {
this.mUnSelectedColor = unSelectedColor;
}
}