Android自定义简单步骤指示器

一,背景

写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;
    }
}
相关推荐
ChinaDragonDreamer1 小时前
Kotlin:2.0.20 的新特性
android·开发语言·kotlin
网络研究院3 小时前
Android 安卓内存安全漏洞数量大幅下降的原因
android·安全·编程·安卓·内存·漏洞·技术
凉亭下3 小时前
android navigation 用法详细使用
android
小比卡丘6 小时前
C语言进阶版第17课—自定义类型:联合和枚举
android·java·c语言
前行的小黑炭7 小时前
一篇搞定Android 实现扫码支付:如何对接海外的第三方支付;项目中的真实经验分享;如何高效对接,高效开发
android
落落落sss8 小时前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
代码敲上天.9 小时前
数据库语句优化
android·数据库·adb
GEEKVIP11 小时前
手机使用技巧:8 个 Android 锁屏移除工具 [解锁 Android]
android·macos·ios·智能手机·电脑·手机·iphone
model200513 小时前
android + tflite 分类APP开发-2
android·分类·tflite
彭于晏68913 小时前
Android广播
android·java·开发语言