Android 自定义View——下载成功

先看效果 

 这个效果主要是由5个部分组成的,

①竖线不断缩短变成小圆点,向下箭头一直存在

②向下箭头逐渐变成水平直线,小圆点一直存在

③小圆点逐渐上升到一定高度,水平直线一直存在

④绘制圆圈

⑤绘制对勾

需要注意的地方是,淡色的圆圈从头到尾都是一直存在的

④和⑤主要是通过PathMeasure来实现的,这里有一个PathMeasure,简单点说,就是用来实现Path坐标点的追踪,就是白色圆圈和对勾已经绘制好了,通过一个进度来不断去部分绘制,最终达到上图的效果。

PathMeasure的常见方法方法含义   

 

       setPath()该方法将path与PathMeasure绑定起来
       getLength()该方法用于获得path路径的长度
       getSegment()该方法用于截取整个Path的片段
       nextContour()该方法用于切换到下一个路径

 

好了,也不多说了,直接贴代码了,注释都已经写清楚了

package com.example.threeversionasproject.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * Created by Ocean on 2019/3/22.
 */

public class DownloadSuccessView extends View {

    //普通画笔
    private Paint mPaint;
    //圆圈画笔
    private Paint mCirclePaint;
    //小圆点画笔
    private Paint mPointPaint;

    //圆心坐标 x,y
    private int centerX, centerY;

    //线的宽度
    private float lineWidth;
    //线长度的二分之一
    private float halfLineLength;
    //圆圈的半径
    private float mCircleRadius;
    //小圆点的半径
    private float mPointRadius;


    //绘制箭头的进度
    float arrowPercent = 0;
    //绘制竖直线的进度
    float linePercent = 0;
    //绘制小圆点的进度
    float pointPercent = 0;
    //绘制圆圈的进度
    float circlePercent = 0;
    //绘制对勾的进度
    float successPercent = 0;


    //用来标识是否正在绘制
    boolean isDraw = true;
    //追踪Path的坐标
    private PathMeasure mPathMeasure;
    private Path mDst;

    public DownloadSuccessView(Context context) {
        super(context);
    }

    public DownloadSuccessView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);//抗锯齿
        mPaint.setDither(true);//防抖动
        mPaint.setStrokeCap(Paint.Cap.ROUND);//末端为圆角
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.STROKE);

        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint.setColor(Color.parseColor("#80FFFFFF"));
        mCirclePaint.setStyle(Paint.Style.STROKE);

        mPointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPointPaint.setColor(Color.WHITE);
        mPointPaint.setStyle(Paint.Style.FILL);

        mPathMeasure = new PathMeasure();
        mDst = new Path();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = measureSize(widthMeasureSpec);
        int height = measureSize(heightMeasureSpec);
        if (width < height) {
            height = width;
        } else {
            width = height;
        }
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = getWidth() / 2;
        centerY = getHeight() / 2;

        mCircleRadius = Math.min(getWidth() - getPaddingLeft() - getPaddingRight(), getHeight() - getPaddingTop() - getPaddingBottom()) / 2 - 6;
        lineWidth = mCircleRadius * 0.1f;
        mPointRadius = lineWidth * 0.75f;
        halfLineLength = mCircleRadius * 0.5f;


        mPaint.setStrokeWidth(lineWidth);
        mCirclePaint.setStrokeWidth(lineWidth);
    }

    public int measureSize(int measureSpec) {
        int defaultSize = 400;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);

        switch (mode) {
            case MeasureSpec.AT_MOST:
                Log.i("", "----------AT_MOST:");
                return Math.min(size, defaultSize);
            case MeasureSpec.EXACTLY:
                Log.i("", "----------EXACTLY:");
                return size;
            case MeasureSpec.UNSPECIFIED:
                Log.i("", "----------UNSPECIFIED:");
                return defaultSize;
            default:
                return defaultSize;
        }
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (isDraw) {
            canvas.drawCircle(centerX, centerY, mCircleRadius, mCirclePaint);
            if (linePercent <= 100) {
                drawLine(canvas);
            } else {
                if (arrowPercent <= 100) {
                    drawArrow(canvas);
                } else {
                    if (pointPercent <= 100) {
                        drawPoint(canvas);
                    } else {
                        if (circlePercent <= 100) {
                            drawCircle(canvas);
                        } else {
                            if (successPercent <= 100) {
                                drawSuccess(canvas);
                            } else {
                                isDraw = false;
                                canvas.drawCircle(centerX, centerY, mCircleRadius, mPaint);

                                Path successPath = drawSuccessPath();
                                canvas.drawPath(successPath, mPaint);
                            }
                        }
                    }
                }
            }
            if (isDraw) {
                //通过延迟刷新达到一种动画的效果
                postInvalidateDelayed(10);
            }
        }
    }

    //再次绘制
    public void reset() {
        if (isDraw == false) {
            arrowPercent = 0;
            linePercent = 0;
            pointPercent = 0;
            circlePercent = 0;
            successPercent = 0;
            isDraw = true;
            invalidate();
        }
    }


    public void drawLine(Canvas canvas) {
        if (linePercent <= 100) {
            canvas.drawLine(centerX, centerY - halfLineLength * (1f - linePercent / 100f), centerX, centerY + halfLineLength * (1f - linePercent / 100f), mPaint);
            Path path = new Path();
            path.moveTo(centerX - halfLineLength, centerY);
            path.lineTo(centerX, centerY + halfLineLength);
            path.lineTo(centerX + halfLineLength, centerY);
            canvas.drawPath(path, mPaint);
            linePercent += 5;
        }
    }

    public void drawArrow(Canvas canvas) {
        if (arrowPercent <= 100) {
            Path path = new Path();
            path.moveTo(centerX - halfLineLength, centerY);
            path.lineTo(centerX, centerY + halfLineLength * (1f - arrowPercent / 100f));
            path.lineTo(centerX + halfLineLength, centerY);
            canvas.drawPath(path, mPaint);
            canvas.drawCircle(centerX, centerY, mPointRadius, mPointPaint);
            arrowPercent += 5;
        }
    }


    public void drawPoint(Canvas canvas) {
        canvas.drawCircle(centerX, centerY - mCircleRadius * 0.8f * (pointPercent / 100f), mPointRadius, mPointPaint);
        canvas.drawLine(centerX - halfLineLength, centerY, centerX + halfLineLength, centerY, mPaint);
        pointPercent += 7;
    }


    public void drawCircle(Canvas canvas) {
        mDst.reset();
        // 硬件加速的BUG
//        mDst.lineTo(0, 0);

        Path path = new Path();
        path.addCircle(centerX, centerY, mCircleRadius, Path.Direction.CW);
        mPathMeasure.setPath(path, false);
        mPathMeasure.getSegment(0, mPathMeasure.getLength() * circlePercent / 100f, mDst, true);
        canvas.drawPath(mDst, mPaint);

        circlePercent += 5;
    }


    public void drawSuccess(Canvas canvas) {
        canvas.drawCircle(centerX, centerY, mCircleRadius, mPaint);
        mDst.reset();
        // 硬件加速的BUG
//        mDst.lineTo(0, 0);
        Path successPath = drawSuccessPath();
        mPathMeasure.nextContour();
        mPathMeasure.setPath(successPath, false);
        mPathMeasure.getSegment(0, successPercent / 100f * mPathMeasure.getLength(), mDst, true);
        canvas.drawPath(mDst, mPaint);
        successPercent += 5;
    }

    //绘制对勾的路径
    public Path drawSuccessPath() {
        Path successPath = new Path();
        successPath.moveTo(centerX - mCircleRadius * 0.4f, centerY);
        successPath.lineTo(centerX - mCircleRadius * 0.1f, centerY + mCircleRadius * 0.3f);
        successPath.lineTo(centerX + mCircleRadius * 0.4f, centerY - mCircleRadius * 0.3f);
        return successPath;
    }
}


以上就是这个自定义view的全部内容,不懂得可以留言。

不断努力,不断进步。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
自定义控件是Android开发中常见的任务之一。下面是一步一步教你如何自定义控件的简要指南: 第一步:创建一个新的Java类作为你的自定义控件。 首先,创建一个新的Java类,可以命名为你想要的控件名称。这个类应该继承自Android框架中的现有控件,例如View、TextView等。例如,如果你想要创建一个自定义按钮,可以创建一个名为CustomButton的类,并让它继承自Button类。 第二步:实现构造函数和属性。 在你的自定义控件类中,你可以实现构造函数和属性,以便对控件进行初始化和设置。你可以定义自己的属性,例如颜色、大小等,以及相应的getter和setter方法。 第三步:重写绘制方法。 要自定义控件的外观,你需要重写它的绘制方法。最常用的方法是重写`onDraw()`方法,在其中使用Canvas绘制你想要的形状、文本等。 第四步:处理用户交互。 如果你的自定义控件需要与用户进行交互,你可以重写相应的触摸事件(例如`onTouchEvent()`)或点击事件(例如`setOnClickListener()`)来处理用户操作。 第五步:在布局文件中使用自定义控件。 完成以上步骤后,你可以在布局文件中使用你的自定义控件了。只需在布局文件中添加一个与你的控件类名相对应的XML标签,并设置相应的属性。 这只是一个简要的指南,帮助你开始自定义控件的过程。在实际开发中,你可能需要更多的步骤和细节来完成你的自定义控件。你可以参考Android官方文档或其他教程来获取更多信息和示例代码
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值