android custom view_ circular progress bar

  • One: Overview:
    Android custom view provides a lot of very rich canvas of operation, the company projects these days need to write a circular progress bar, take this opportunity to talk about the basic operation of the canvas
  • Two: the desired effect
    effect I want to achieve in Figure:
    Write pictures described here
    This is a grade renderings, requirements can be based on user level, the rest position of the dynamic changes in the blue progress bar.
    Three: the realization of ideas:
    Canvas can draw a lot of basic graphics: rectangle, circle, rounded rectangle, fan ...
    my first thought is implemented according to the picture painted in radians, is a fan.
    Because there is a need across the animation, it is not time to finish the painting, a painting that, in multiple unfinished.
    There are two ideas:
    as 1 starting position, each painted a different arc.
    2. Each arc as painting, dynamically calculated start position.
    The first idea to implement simple and crude, where you choose the first direct.
    This custom view of the difficulties is when the animation completes the calculation end position slightly trouble, we use some knowledge of geometry, if you forget to go looking through junior high school mathematics textbooks of it.

Four: code to achieve:
some variables that we defined, I wrote a note:

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;//定义圆周率

First, in the initialization time, we made some operations

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

OnSizeChanged initialization function in the brush painting a rectangular area 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);
}

Below is our core ondraw method, and inside there is some logic: I have done a detailed notes

    @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);
    }

After the completion of the circle we have a way to calculate the rest position getStarPos (), in the calculation, we used the ratio of the circumference, are some die method, as follows:

    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;
        }
    }

In order to coordinate the unfinished passed to the outside world, the definition of an excuse to listen

    @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);
    }

Above is the whole process of the realization of our. If those who do not understand or believe nothing wrong with it, please give me a message below.
Below is the source address, inside a detailed usage.
Download Source github

Published 17 original articles · won praise 12 · views 10000 +

Guess you like

Origin blog.csdn.net/qq_24295537/article/details/52529170