教你玩转自定义View—手撸一个倒计时控件如此简单

2,805 阅读3分钟

在一个APP启动的时候呢,一般经常见到倒计时3秒或几秒的场景,在这个场景中,也经常看到一个有动画加载的view,效果图如下:

倒计时效果图
倒计时效果图

分析

正所谓知己知彼百战百胜,所以我们每去做一件事情之前都要去花费一定的时间去了解一些相关的东西。那么这样的一个效果呢其实不难,我们只需两个东西即可实现。——canvas和属性动画。

1.自定义我们需要的属性:

那么为了考虑扩展性,那么有些属性呢我们不能写死,自定义属性是最好的选择!首先在values文件夹下新建文件attrs.xml

<declare-styleable name="CountDownView">
        <!--view半径-->
        <attr name="cd_circle_radius" format="dimension" />
        <!--画笔宽度-->
        <attr name="cd_arc_width" format="dimension" />
        <!--画笔颜色-->
        <attr name="cd_arc_color" format="color" />
        <!--背景颜色-->
        <attr name="cd_bg_color" format="color" />
        <!--字体颜色-->
        <attr name="cd_text_color" format="color" />
        <!--字体尺寸-->
        <attr name="cd_text_size" format="dimension" />
        <!--动画执行时长-->
        <attr name="cd_animator_time" format="integer" />
        <!--时间单位-->
        <attr name="cd_animator_time_unit" format="string" />
        <!--动画进退方式-->
        <attr name="cd_retreat_type" format="enum">
            <!--外层的圆弧逐渐变长-->
            <enum name="forward" value="1" />
            <!--外层的圆弧逐渐减短-->
            <enum name="back" value="2" />
        </attr>
        <!--加载进度的开始位置-->
        <attr name="cd_location" format="enum">
            <enum name="left" value="1" />
            <enum name="top" value="2" />
            <enum name="right" value="3" />
            <enum name="bottom" value="4" />
        </attr>
    </declare-styleable>

然后在自定义View中获取并设置这些属性:
首先,来声明和获取定义好的属性:

private Paint mPaintBackGround;//背景画笔
    private Paint mPaintArc;//圆弧画笔
    private Paint mPaintText;//文字画笔
    private int mRetreatType;//圆弧绘制方式(增加和减少)
    private float mPaintArcWidth;//最外层圆弧的宽度
    private int mCircleRadius;//圆圈的半径
    private int mPaintArcColor = Color.parseColor("#3C3F41");//初始值
    private int mPaintBackGroundColor = Color.parseColor("#55B2E5");//初始值
......

获取这些属性值:

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CountDownView);
mRetreatType = array.getInt(R.styleable.CountDownView_cd_retreat_type, 1);
location = array.getInt(R.styleable.CountDownView_cd_location, 1);

初始化画笔等操作:

2.画出需要的效果:画圆弧,画字体,画背景

这里我们使用cancas的drawArc()方法,不了解这个方法是什么意思的请跳至此处查看详细解释~drawArc()方法详细介绍

环形进度
环形进度

3.改变属性值,重新绘制

4.接口回调。

这一步就很简单了,只要监听动画执行结束就是完成了加载,所以我们先来写一个接口。

private OnLoadingFinishListener loadingFinishListener;

    public void setOnLoadingFinishListener(OnLoadingFinishListener listener) {
        this.loadingFinishListener = listener;
    }

    public interface OnLoadingFinishListener {
        void finish();
    }

在对应的Activity中回调接口就可以了。

OK,到这里就算全部结束了,下面是部分源码:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //因为必须是圆形的view,所以在这里重新赋值
        setMeasuredDimension(mCircleRadius * 2, mCircleRadius * 2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画北景园
        canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2 - mPaintArcWidth, mPaintBackGround);
        //画圆弧
        RectF rectF = new RectF(0 + mPaintArcWidth / 2, 0 + mPaintArcWidth / 2
                , mWidth - mPaintArcWidth / 2, mHeight - mPaintArcWidth / 2);
        canvas.drawArc(rectF, startAngle, mSweepAngle, false, mPaintArc);
        //画文字
        float mTetxWidth = mPaintText.measureText(mText, 0, mText.length());
        float dx = mWidth / 2 - mTetxWidth / 2;
        Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt();
        float dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
        float baseLine = mHeight / 2 + dy;
        canvas.drawText(mText, dx, baseLine, mPaintText);

    }

博客地址:

www.jianshu.com/p/2b5ef5e18…

项目地址:

github.com/SuperKotlin…

相信自己,没有做不到的,只有想不到的

如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809
微信公众号:终端研发部

技术+职场
技术+职场