android 自定义view_圆形进度条

  • 一:概述:
    android的自定义view提供了很多很丰富的画布操作,这几天公司的项目需要写一个圆形进度条,借着这个机会,说一下画布的基本操作
  • 二:预期效果
    我要实现的效果如图:
    这里写图片描述
    这是一个等级效果图,要求可以根据用户的等级,动态的改变蓝色进度条的停留位置。
    三:实现思路:
    canvas可以画很多基本的图形:长方形,圆形,圆角长方形,扇形…
    根据图片我第一时间想到的就是用画弧度实现,也就是扇形。
    由于需要有一个划过的动画,所以不能一次就画完,一次画一点,分多次画完。
    这里有两种思路:
    1.起始位置一样,每次画的弧度不同。
    2.每次画的弧度一样,起始位置动态计算。
    第一种思路实现起来简单粗暴,在这里直接选择第一种。
    这个自定义view的难点就是在动画完成的时候计算结束位置有些许的麻烦,用到了一些几何知识,如果忘了就去翻翻初中的数学课本吧。

四:代码实现:
我们定义的一些变量,我都写了注释:

private RectF rectF;
    private double sweepRadius = 0;//扫过的角度(默认是0)
    boolean isRunning;//运行的控制器
    float radius = 1f;//每一帧画完之后的角度
    float speedRadius = 10f;//每次画的角度(可以理解为速度)
    float starttPoint = 270f;//初始化的角度(默认在中间顶部
    private Paint mPaint;
    private int paintWidth = 2;//画笔的宽度
    float finalRadius=0;
    double pi =3.14159265358979323846264338327950288419716939937510582097494459230781640628620899;//定义圆周率

首先在初始化的时候,我们做了一些操作

mPaint = new Paint();
mPaint.setColor(0xff1ecfff);//画笔的颜色
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(paintWidth);//画笔的宽度
mPaint.setAntiAlias(true);//设置抗锯齿

在onSizeChanged函数中初始化画笔的绘画区域矩形rectF

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
   super.onSizeChanged(w, h, oldw, oldh);
   rectF = new RectF(paintWidth,paintWidth,getWidth()-paintWidth,getHeight()-paintWidth);
}

下边就是我们的核心ondraw方法了,里边有一些逻辑:我都做了详细的注释

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

        canvas.drawColor(Color.WHITE);//画布背景颜色

        if (sweepRadius==0) return;//如果扫过的角度为0,则不用画

        if (finalRadius!=0){
            canvas.drawArc(rectF, starttPoint, finalRadius, false, mPaint);
            return;
        }

        canvas.drawArc(rectF, starttPoint, radius, false, mPaint);

        radius=radius+speedRadius ;
        if (radius >= sweepRadius+1f){
            //画圆结束
            finalRadius = radius-speedRadius;
            isRunning = false;
            sweepRadius = finalRadius;//重新确切的告诉view扫过的角度
            getStarPos();//计算画完后的坐标的方法
            if (listener!=null){
                listener.onDrawFinish(starX , starY);
            }
        }

        if (!isRunning) return;
        //刷新view,每50毫秒执行一次ondraw()
        postInvalidateDelayed(50);
    }

在画圈完成后我们有一个计算停留位置的方法getStarPos(),在计算的过程中,我们用到了圆周率,都是一些死方法,代码如下:

    private double starX;// x坐标
    private double starY;// y坐标
    /**
     * 得到画圈后的坐标点
     */
    public void getStarPos(){
        double r = (getWidth()-paintWidth*2)/2;//半径

        if (sweepRadius==0){
            starX = r;
            starY = 0;
        }else if (sweepRadius < 90d){
            starX = r + Math.sin(sweepRadius*pi/180)*r;
            starY = r - Math.cos(sweepRadius*pi/180)*r;
        }else if (sweepRadius == 90d){
            starX = r*2;
            starY = r;
        }else if (sweepRadius < 180d){
            starX = r+Math.cos((sweepRadius-90d)*pi/180)*r;
            starY = r+Math.sin((sweepRadius-90d)*pi/180)*r;
        }else if (sweepRadius == 180d){
            starX = r;
            starY = r*2;
        }else if (sweepRadius < 270d){
            starX = r - Math.sin((sweepRadius-180d)*pi/180)*r;
            starY = r + Math.cos((sweepRadius-180d)*pi/180)*r;
        }else if (sweepRadius == 270d){
            starX = 0;
            starY = r;
        }else if (sweepRadius < 360d){
            starX = r - Math.cos((sweepRadius-270d)*pi/180)*r;
            starY = r - Math.sin((sweepRadius-270d)*pi/180)*r;
        }
    }

为了把画完后的坐标传给外界,定义了一个借口监听

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
    }

    private OnDrawingFinishListener listener;
    public void setOnDrawingFinishListener(OnDrawingFinishListener onDrawingFinishListener){
        this.listener = onDrawingFinishListener;
    }
    public interface OnDrawingFinishListener{
        void onDrawFinish(double xPos, double yPos);
    }

以上就是我们的全部实现过程了。如有那些不理解或认为不妥的地方,请在下方给我留言。
下边是源码地址,里边有详细的用法。
github下载源码

发布了17 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_24295537/article/details/52529170