# The realization of circular progress bar with progress

Today, a circular progress bar with progress is implemented by customizing the View. The final effect is shown in the following figure:

Now let's talk about the design idea: first of all, this progress bar can customize the number of small rounded rectangles, the size of small rounded rectangles, the angle of small rounded rectangles, the color of unfinished progress, the color, text size, text color and circle radius when the progress is completed, so you need to customize these parameters; then how to draw this round progress? We need to draw a small rounded rectangle first, and then rotate the canvas to draw a rectangle. As shown in the figure, there are 12 small rounded rectangles, each rotating 360 / 12 = 30 degrees, drawing a small rounded rectangle, a total of 12. Then draw the progress value in the middle, and draw the progress value in the middle. It mainly needs to calculate the position of the text, which will be introduced later. Next, the implementation process is explained in detail through the code. The code is as follows:

```import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.support.annotation.FloatRange;
import android.support.annotation.Nullable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/**
* Created by Liu xinon April 27, 2018
*/

public class LoadView extends View {
//The width of a small rectangle
private int mRectangleWidth;
//Height of small rectangle
private int mRectangleHeight;
//Number of small rectangles
private int mRectangleNum;
//Small rectangle circle angle
//Inside radius refers to the size of the block not included
//Text size
private int mTextSize;
//Paint brush
private Paint mPaint;
//A brush for writing
private TextPaint mTextPaint;
//Small rectangle
private RectF mRectF;

private Context mContext;
//Percentage string
private String mPercentStr;
//Percentage
private float mPercent;

this(context, null);
}

public LoadView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}

public LoadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}

private void init(Context context, AttributeSet attrs, int deStyleAttr) {
mContext = context;
TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.LoadView, deStyleAttr, 0);
//Here are the default values for some custom parameters
mRectangleWidth = dipToPixels(mContext, 14);
mRectangleHeight = dipToPixels(mContext, 28);
mRectangleNum = 12;
mTextSize = dipToPixels(mContext, 48);
mPercentStr = "0%";
mPercent = 0f;
if (typedArray != null) {
//Read these parameter settings from xml
typedArray.recycle();
}
//The outer radius is equal to the user set inner radius plus the height of the small rectangle
//Here is the RetcF needed to draw the first circular rectangle. It is determined by the coordinates of the upper left corner and the lower right corner,
// Here, the coordinates of the upper left corner (mOuterRadius - mRectangleWidth / 2f,0),
//The coordinates of the lower right corner (mOuterRadius + mRectangleWidth / 2f, mRectangleHeight);
mRectF = new RectF(mOuterRadius - mRectangleWidth / 2f, 0, mOuterRadius + mRectangleWidth / 2f, mRectangleHeight);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mTextPaint = new TextPaint();
//You can also set the font of the text here. I have removed it
/*try {
mTextPaint.setTypeface(typeface);
} catch (Exception e) {
e.printStackTrace();
}*/
mTextPaint.setTextSize(mTextSize);

}

private int dipToPixels(Context context, float dip) {
final float SCALE = context.getResources().getDisplayMetrics().density;
float valueDips = dip;
int valuePixels = (int)(valueDips * SCALE + 0.5f);
return valuePixels;
}

/**
*For external calls
* Please call in the main thread to set the progress from 0 to 1
* @param percent
*/
public void setPercent(@FloatRange(from=0.0, to=1.0) float percent){
this.mPercent=percent;
this.mPercentStr=Math.round(percent*100)+"%";
invalidate();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Forced width height, invalid setting width height in xml file
//Set the size according to the radius and small rectangle size
int defaultSize = 2 * (mInnerRadius + mRectangleHeight);
setMeasuredDimension(defaultSize, defaultSize);

}

@Override
protected void onDraw(Canvas canvas) {
int hasDownCount = 0;//How many loaded rectangles do you need to draw to convert the downloaded percentage
hasDownCount = Math.round(mPercent * mRectangleNum);//Only round
//Save the state of the canvas before rotating
canvas.save();
//Required angle for each rotation
float degress = 360.0f / mRectangleNum;
for (int i = 0; i < mRectangleNum; i++) {

if (hasDownCount > i) {
} else {
}
//round rectangle
//Rotate the canvas at the center. Here, imagine you draw on the paper with a pen in reality. When you draw one, you will rotate the paper, and you will know
}
//Go back to the previous canvas state
canvas.restore();
//Text width
float textWidth = mTextPaint.measureText(mPercentStr);
//Pay attention to the calculation of height
//drawText is based on the BaseLine of the text
//So the steps to calculate the height: half of the descent ascent minus descent; the result
// It's the offset of Baseline from the center dot, and the radius is the height
//Not yet? Look at the picture below
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
float diffBaseLine = (-(fontMetrics.ascent + fontMetrics.descent)) / 2;
//By default, x is the position of the left side of the string on the screen. If paint.setTextAlign(Paint.Align.CENTER) is set, that is the center of the character, y is the position of the baseline on the screen