Custom Circle progress bar Custom Countdown progress bar
Copyright NOTICE: Reprint must indicate this article transferred from Zhangjie's blog: http://blog.csdn.net/yanzhenjie1003
This control source is open source to Github:https://github.com/yanzhenjie/circletextprogressbar, Welcome to star.
Welcome to join my blog on the left side of the QQ Exchange Group to explore.
Effect Preview
Source Code Portal:Https://github.com/yanzhenjie/CircleTextProgressbar
Implementation and principle
This text round progress bar we have seen in many apps, such as the app Welcome page countdown, download file countdown, etc.
Analysis of the principle, maybe some students see this custom view on the panic, this is not to inherit the view Ah, is not to draw Ah, the answer is: yes. But let's not worry, it's really easy to achieve this effect. Let's take a look at core analysis and code with me.
Principle Analysis
First we observe that several components are required:
1. The round progress bar is gradually increased/decreased outside.
2. The display text in the middle of the round progress bar.
3. Round the round progress bar wrap the circle outside.
4. Fill color in the middle of the round progress bar.
5. Font color/Fill Color Click Color: ColorStateList
class.
We analyzed the need for four parts. A look at the text, then the first thought of the nature is TextView
, just can do less a font color record. The middle of the fill color (the prototype is not considered) color change when clicked, need ColorStateList
class to record. The rest of the progress bar, Contour circle and fill circle is what we need to draw.
The process of stepping on a pit
In fact, for a long time did not write a custom view, some things have really forgotten, so write this view and put the previous pit tread again, in order to avoid other students also be pits, here I tread on the pit also recorded.
View Drawing Area
Here I have a problem, because we inherit the TextView
text more is long, then draw out the circle length is the same, so the circle drawn on the TextView can only see part or ellipse. So we're going to View
expand the drawing area. I first thought of the layout()
method, because when View
the parent layout is onLayout()
called View
layout()
to let the child View
layout, I rewrite the layout
method:
@Overridepublicvoidlayout(intintintint bottom) { int w = right - left; int h = bottom - top; int size = w > h ? w : h; if (w > h) { bottom += (size - h); else { right += (size - w); } super.layout(left, top, right, bottom);}
The principle of this code is wide and high, that large, the view to expand to this maximum value.
When I put a View
on Layout
, the effect is fine, but I put multiple View
to linearlayout
I found several View
overlaps, oh Seth. It dawned on me that the Nima people Layout
had specified the width of my plot area, and I forcibly occupied the other View
. So, I should rewrite onmeasure ()
, and tell the parent Layout
What size I want when I measure my height:
@OverrideprotectedvoidonMeasure(intint heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = getMeasuredWidth(); int height = getMeasuredHeight(); int size = width > height ? width : height; setMeasuredDimension(size, size);}
The meaning of this code is easier to understand, that is, super.onMeasure
when measuring the width of the height of which large, the width is set to the largest of this value. Tell the father how Layout
old I want to be, so when I draw I want to play as much as I can.
Implementation of Drawing view
OK, come to the key place, the front is all done and see how we draw our circle of several circles. It is necessary to rewrite the method in circle circles onDraw()
.
First you need a brush:
new Paint();mPaint.setAntiAlias(true);// 抗锯齿
Get the drawing area.
We can get to the drawing area by Getdrawingrect (Rect) and calculate the radius of the circle by drawing the area.
new Rect();@OverrideprotectedvoidonDraw(Canvas canvas) { getDrawingRect(bounds);//获取view的边界 int size = bounds.height() > bounds.width() ? bounds.width() : bounds.height(); float2// 计算出绘制圆的半径}
Draw a Fill circle
So we're going to have to use ColorStateList
this to do an initialization and to support the definition of this attribute in XML:
// 默认透明填充。ColorStateList inCircleColors = ColorStateList.valueOf(Color.TRANSPARENT);privatevoidinitialize(Context ctx, AttributeSet attributeSet) { TypedArray typedArray = ctx.obtainStyledAttributes(attributeSet, R.styleable.Progressbar); inCircleColors = typedArray.getColorStateList(R.styleable.Progressbar_circle_color); typedArray.recycle();}
Students who do not understand how to customize the view XML properties request Google for themselves.
The color of the filled circle is drawn according to the Click, Check, select State, because it is filled, so here Paint
Style
is FILL
:
int0);mPaint.setStyle(Paint.Style.FILL);mPaint.setColor(circleColor);canvas.drawCircle(bounds.centerX(), bounds.centerY(), outerRadius - outLineWidth, mPaint);
The center is the center of the drawing area, and the radius is the width of the 绘制区域圆
radius minus 外部轮廓圆线
. This just fills the circles and the outer contour circles do not overlap.
Draw an outer border circle
This is simple because it is a hollow line, so Style
Yes STROKE
, then set the width of the line, the color of the brush:
2, mPaint);
The center of the Circle is the center of the drawing area, and the radius is half the width of the radius 绘制区域圆
minus 外部轮廓圆线
, so that the outer contour line and the inner fill circle close.
Draw
TextView
The word
For our drawing and our TextView
own drawing does not overlap, we kill super.onDraw(canvas);
, so here we have to put TextView word also to write up.
First get TextView
The default brush, set TextView
its own font color, anti-aliasing, for the sake of beauty we forcibly let the text center:
//画字Paint paint = getPaint();paint.setColor(getCurrentTextColor());paint.setAntiAlias(true);paint.setTextAlign(Paint.Align.CENTER);float2;canvas.drawText(getText().toString(), bounds.centerX(), textY, paint);
Draw a progress bar
The progress bar is not a circle. Oh, exactly, it's an arc,
The brush uses the default brush, sets the color, sets the width of the line, and Style
STROKE
finally specifies the drawing area and center point, angle:
RECTF Marcrect =NewRECTF (); Rect bounds =NewRect ();@Overrideprotected void OnDraw(Canvas canvas) {Getdrawingrect (bounds);//Get the boundary of the view...//Draw a progress bar arc. Mpaint.setcolor (Progresslinecolor); Mpaint.setstyle (Paint.Style.STROKE); Mpaint.setstrokewidth (Progresslinewidth); Mpaint.setstrokecap (Paint.Cap.ROUND);intDeletewidth = Progresslinewidth + outlinewidth;//Specify drawing areaMarcrect.set (Bounds.left + deletewidth/2, Bounds.top + deletewidth/2, Bounds.right-deletewidth/2, Bounds.bottom-deletewidth/2); Canvas.drawarc (Marcrect,0, the* Progress/ -,false, mpaint);}
Here the difficulty in specifying the drawing area, because the external contour lines can not be covered, so close to the outer contour of the interior painting, so to the outermost draw circle area, so to subtract (the outer Circle line width + progress bar width)/2 The boundary is the progress bar.
Complete code for drawing and measurement
Here the key code is finished, you can write a test yourself, I here to the full onDraw()
and onMeasure()
the source of the paste out:
Private intOutLineColor = Color.Black;Private intOutlinewidth =2;PrivateColorstatelist incirclecolors = colorstatelist.valueof (color.transparent);Private intCirclecolor;Private intProgresslinecolor = Color.Blue;Private intProgresslinewidth =8;PrivatePaint Mpaint =NewPaint ();PrivateRECTF Marcrect =NewRECTF ();Private intProgress = -;FinalRect bounds =NewRect ();@Overrideprotected void OnDraw(Canvas canvas) {//Get the boundary of the viewGetdrawingrect (bounds);intSize = Bounds.height () > Bounds.width ()? Bounds.width (): Bounds.height ();floatOuterradius = size/2;//Draw internal background intCirclecolor = Incirclecolors.getcolorforstate (Getdrawablestate (),0); Mpaint.setstyle (Paint.Style.FILL); Mpaint.setcolor (Circlecolor); Canvas.drawcircle (Bounds.centerx (), Bounds.centery (), Outerradius-outlinewidth, mpaint);//Draw Border CircleMpaint.setstyle (Paint.Style.STROKE); Mpaint.setstrokewidth (Outlinewidth); Mpaint.setcolor (OutLineColor); Canvas.drawcircle (Bounds.centerx (), Bounds.centery (), Outerradius-outlinewidth/2, Mpaint);//stoopedPaint paint = getpaint (); Paint.setcolor (Getcurrenttextcolor ()); Paint.setantialias (true); Paint.settextalign (Paint.Align.CENTER);floatTexty = Bounds.centery ()-(paint.descent () + paint.ascent ())/2; Canvas.drawtext (GetText (). toString (), Bounds.centerx (), texty, paint);//Draw progress barMpaint.setcolor (Progresslinecolor); Mpaint.setstyle (Paint.Style.STROKE); Mpaint.setstrokewidth (Progresslinewidth); Mpaint.setstrokecap (Paint.Cap.ROUND);intDeletewidth = Progresslinewidth + outlinewidth; Marcrect.set (Bounds.left + deletewidth/2, Bounds.top + deletewidth/2, Bounds.right-deletewidth/2, Bounds.bottom-deletewidth/2); Canvas.drawarc (Marcrect,0, the* Progress/ -,false, mpaint);}@Overrideprotected void onmeasure(intWidthmeasurespec,intHEIGHTMEASURESPEC) {Super. Onmeasure (Widthmeasurespec, Heightmeasurespec);intLineWidth =4* (Outlinewidth + progresslinewidth);intwidth = Getmeasuredwidth ();intHeight = getmeasuredheight ();intSize = (Width > Height width:height) + linewidth; Setmeasureddimension (size, size);}
Above full Source: Https://github.com/yanzhenjie/CircleTextProgressbar, welcome star.
Copyright NOTICE: Reprint must indicate this article transferred from Zhangjie's blog: http://blog.csdn.net/yanzhenjie1003
Custom Circle progress bar Custom Countdown progress bar