当前位置:首页 > 未命名 > 正文内容

Custom View——How to design and implement a circularity progress bar

u3blog8年前 (2016-04-07)未命名174

Requirements analysis and implementation planning

Introduction

Recently i have use douban fm app and i like the circularity progress bar in this app, so i think to write a same one. There is the progressbar in douban fm:

functional analysis

Although the function is simple, but still needs careful analysis 1.There is a circul outside of the icon, You can set the width 2.Circular progress bar and background at the bottom,you can set the width, color, and so on 3.The inside has a rounded picture, can rotate

Analysis for implementation

1.The circle that you can set the width

This is easy,You can use canvas to draw directly in the ondraw Method,of course,we need careful on radiu and padding,the control itself is actually a rectangle,we need to select a shorter as the diameter,Also have to deal with internal padding

2.Circular progress bar and progress bar at the bottom, you can set the width, color, and so on

This can be achieved with canvas drawarc Method,showing the progressbar by draw different length of arch,but it is important to note,We need to calculate the radius of the arc, and start and end points.

3.The inside has a rounded picture, can be rotated

This demand can be divided into three parts, there are pictures, round, you can rotate First a picture,Simple,canvas and drawbitmap can draw it(canvas is so strong) Round,still use canvas to control bitmap to draw it, you can see the detail in code finally can rotate,we can use canvas rotate method to implement it.

show

Here is a show of the final look That is my own project here

code

below is the code and some comment Our main work It was in a custom view's onDraw method,so,We need to have a child class that inherits the view class,MyProgress, we'll call him we show the MyProgress's onDraw method

1.a circule can set width

This is easy,You can use canvas to draw directly in the ondraw Method,of course,we need careful on radiu and padding
super.onDraw(canvas);  //need invoke parent's onDraw

        final int paddingLeft = getPaddingLeft();
        final int paddingRight = getPaddingRight();
        final int paddingTop = getPaddingTop();
        final int paddingBottom = getPaddingBottom();  //get padding

        //get the view's width and height and decide the radiu
        int width = getWidth() - paddingLeft - paddingRight;
        int height = getHeight() - paddingTop - paddingBottom;
        radiu = Math.min(width , height) / 2 - boundWidth - progressWidth;  //calculate radius,chose the short one,boundWidth is the circul's width,progressWidth is the progress bar's width

        //setup the paint
        paint.setStyle(Paint.Style.STROKE); //Set the paint to outline
        paint.setStrokeWidth(boundWidth);   //set width
        paint.setColor(Color.BLACK);        //set color

        //draw the inner circle
        int centerX = paddingLeft + getWidth()/2;
        int centerY = paddingTop + getHeight() / 2;  //Calculation of the center point of the circle
        canvas.drawCircle(centerX,centerY, radiu, paint);  //draw circular
 

2.Circular progress bar and progress bar at the bottom, you can set the width, color, and so on

We need change the start and end point of the arch
  
        //set paint for arc
        paint.setStrokeWidth(progressWidth);
        paint.setStrokeCap(Paint.Cap.ROUND);//Sets the width of the progress, setting the end is a circular arc

        //prepare for draw arc
        RectF oval = new RectF();
        oval.left = centerX -totalRadiu ;
        oval.top =centerY- totalRadiu ;
        oval.right =  centerX + totalRadiu;
        oval.bottom = centerY+ totalRadiu; //A new ellipse, sets the coordinates of four points
        paint.setColor(progressBackColor);//Sets the background color of the progress bar

        //draw background arc
        canvas.drawArc(oval, arcStar, arcEnd, false, paint); //Draw a circular arc at the bottom, as a background

        //draw progress arc
        paint.setColor(progressColor);//Sets the color of the progress bar
        canvas.drawArc(oval, arcStar, progress, false, paint);//draw progress bar

3.The inside has a rounded picture, can be rotated

 

       float  totalRadiu = radiu +boundWidth  +progressWidth/2;//set outside radiu

        //draw the circlr pic
        if (drawable != null&&bitmap == null) {
            image = ((BitmapDrawable) drawable).getBitmap();//get bitmap resource

            bitmap = Bitmap.createBitmap((int)(2*totalRadiu),(int)(2*totalRadiu), Bitmap.Config.ARGB_8888);
            Canvas bitmapCanvas = new Canvas(bitmap);//create a bitmap and a canvas to control it

            Paint bitmapPaint = new Paint();
            bitmapPaint.setAntiAlias(true);//create a new paint and set antialias

            bitmapCanvas.drawCircle(totalRadiu, totalRadiu, radiu, bitmapPaint);//draw a circular

            bitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//key code,Set to intersect mode,and later there will be content to get the intersection
            bitmapCanvas.drawBitmap(image,null,new RectF(0,0,2*totalRadiu,2*totalRadiu) , bitmapPaint);//Draw your own picture to an existing canvas

        }
        Rect rect = new Rect((int)(centerX -totalRadiu),(int)(centerY-totalRadiu),(int)(centerX+totalRadiu),(int)(centerY+ totalRadiu));//Create a new RECT, set the boundary point
        canvas.save();
        if(isRotate)
        canvas.rotate(rotateDegree,centerX,centerY);//Set the rotation, in order to achieve picture rotation effect, rotateDegree is the rotation angle
        canvas.drawBitmap(bitmap,null ,rect, paint);//Draw  picture
so that's our ondraw method

full code

MyProgress.java
public class MyProgressBar extends View {
    float progress = 360;
    float arcStar = 270;
    float arcEnd = 360;
    double rotateStep = 0.2;
    Bitmap bitmap;
    int totalTime;
    Bitmap image;
    Drawable drawable;
    int boundWidth = 5;
    private int progressWidth = 30;
    private boolean isRotate = false;
    private int progressColor = Color.GREEN;
    private int progressBackColor = Color.GREEN;
    private float rotateDegree = 0;


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

    public MyProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private float radiu;
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    public void setRadiu(float radiu) {
        this.radiu = radiu;
        invalidate();
    }
//start 函数使用 countDownTimer类来更新progress和旋转角度
    public void start(long time) {
        bitmap = null;

        time *= 60000;
        final float step = (float) 360 / (time / 30);
        CountDownTimer mTimer = new CountDownTimer(time, 30) {
            public void onTick(long millisUntilFinished) {
                progress -= step;
                rotateDegree -= rotateStep;
                invalidate();
            }

            @Override
            public void onFinish() {
                end(step);
            }

        };
        mTimer.start();
    }

    private void end(float step) {
        progress -= step;
        invalidate();
        progress = 0;
        rotateDegree = 0;
        invalidate();
    }

    public void setBoundWidth(int width) {
        boundWidth = width;
    }

    public void setProgressWidth(int width) {
        progressWidth = width;
    }

    public void setProgressColor(int color) {
        progressColor = color;
    }

    public void setProgressBackColor(int color) {
        progressBackColor = color;
    }

    public void setDrawable(Drawable drawable) {
        this.drawable = drawable;
        invalidate();
    }
    public void setIsRote(boolean rotate)
    {
        this.isRotate = rotate;
        invalidate();
    }

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

        final int paddingLeft = getPaddingLeft();
        final int paddingRight = getPaddingRight();
        final int paddingTop = getPaddingTop();
        final int paddingBottom = getPaddingBottom();

        //get the view's width and height and decide the radiu
        int width = getWidth() - paddingLeft - paddingRight;
        int height = getHeight() - paddingTop - paddingBottom;
        radiu = Math.min(width , height) / 2 - boundWidth - progressWidth;

        //setup the paint
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(boundWidth);
        paint.setColor(Color.BLACK);

        //draw the inner circle
        int centerX = paddingLeft + getWidth()/2;
        int centerY = paddingTop + getHeight() / 2;
        canvas.drawCircle(centerX,centerY, radiu, paint);
        

        float  totalRadiu = radiu +boundWidth  +progressWidth/2;

        //draw the circlr pic
        if (drawable != null&&bitmap == null) {
            image = ((BitmapDrawable) drawable).getBitmap();

            bitmap = Bitmap.createBitmap((int)(2*totalRadiu),(int)(2*totalRadiu), Bitmap.Config.ARGB_8888);
            Canvas bitmapCanvas = new Canvas(bitmap);

            Paint bitmapPaint = new Paint();
            bitmapPaint.setAntiAlias(true);

            bitmapCanvas.drawCircle(totalRadiu, totalRadiu, radiu, bitmapPaint);

            bitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            bitmapCanvas.drawBitmap(image,null,new RectF(0,0,2*totalRadiu,2*totalRadiu) , bitmapPaint);


        }
        Rect rect = new Rect((int)(centerX -totalRadiu),(int)(centerY-totalRadiu),(int)(centerX+totalRadiu),(int)(centerY+ totalRadiu));
        canvas.save();
        if(isRotate)
        canvas.rotate(rotateDegree,centerX,centerY);
        canvas.drawBitmap(bitmap,null ,rect, paint);

        canvas.restore();
        //set paint for arc
        paint.setStrokeWidth(progressWidth);
        paint.setStrokeCap(Paint.Cap.ROUND);

        //prepare for draw arc
        RectF oval = new RectF();
        oval.left = centerX -totalRadiu ;
        oval.top =centerY- totalRadiu ;
        oval.right =  centerX + totalRadiu;
        oval.bottom = centerY+ totalRadiu;
        paint.setColor(progressBackColor);

        //draw background arc
        canvas.drawArc(oval, arcStar, arcEnd, false, paint);

        //draw progress arc
        paint.setColor(progressColor);
        canvas.drawArc(oval, arcStar, progress, false, paint);
    }

}
You can find the project on GitHubhere

summary

There are some problem worth to think 1.on clipping pictrue,need to note the canvas's coodinate Is relative to the picture,Instead of the global coordinates 2.when draw,need reduce draw a pic multiple time,Such as cropping rounded picture ,one time is enough. 3.For the few key points coordinates of the Custom View,should use a clarity way to present. 4.You can if you start to do

扫描二维码推送至手机访问。

版权声明:本文由u3blog发布,如需转载请注明出处。

本文链接:https://u3blog.xyz/?id=304

分享给朋友:

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。