Android Custom Round countdown progress bar _android

Source: Internet
Author: User
Tags border color drawtext gettext int size xml attribute

Effect Preview

Source code Transfer Gate: Https://github.com/yanzhenjie/CircleTextProgressbar

Realization and principle

We've seen it in many apps, such as app welcome page countdown, download file countdown, etc.

Analysis of the principle, may be some students see this custom view on the panic, this is not to inherit view Ah, is not to draw ah and so on, the answer is: yes. But let us not worry, it is so easy to achieve this effect. Now let's take a look at the core analysis and code.

Principle Analysis

First, we look at the above picture and we need several parts:
1. The outside gradually increases/decreases the circular progress bar.
2. The display text in the middle of the circular progress bar.
3. Round of the round progress strip wrapped.
4. The fill color in the middle of the circular progress bar.
5. Font color/Fill Color Click Discoloration: Colorstatelist class.

We need four parts for our analysis. A look at the text, then the first thought of the nature is TextView, just can be less to do a record of font color. The middle of the fill color (the prototype is not considered) click on the discoloration, you need to colorstatelist class to record. The rest of the progress bar, outline and fill circle are needed for us to draw.

Circletextprogressbar Features of my package

Circletextprogressbar support automatic countdown, automatic reduction of progress, automatic increase in progress and so on.

If you need to automatically enter the degree, after setting up your custom attributes call the start () method can automatically countdown, if you want to go after the automatic Progress call restart () ok.

If you do not want to automatically walk into degrees, you can modify the progress values by setprogress () like the progress of the system.

As with the system normal progress bar, 0-100.
Progressbar.setprogresstype (CircleTextProgressbar.ProgressType.COUNT);
Change the progress bar.
Progressbar.setprogresslinewidth (30);//progress bar width.
//Set countdown time milliseconds, default 3000 milliseconds.
Progressbar.settimemillis (3500);
Change the progress bar color.
Progressbar.setprogresscolor (color.red);
Change the outer border color.
Progressbar.setoutlinecolor (color.red);
Change the center color.
Progressbar.setincirclecolor (color.red);
If you need to automatically countdown, you will automatically enter the degree.
Progressbar.start ();
If you want to set up your own progress, such as 100.
progressbar.setprogress (100);

The process of stepping on a pit

In fact, I have not written a custom view for a long time, some things really forget, so write this view when the previous pit trample again, in order to avoid other students are also pits, where I stepped on the pit also recorded.

View Draw Area

Here I encountered a problem, because we inherited more textview text is long, then draw out the circle is the same width, so the circle drawn on the TextView can only see a part or an ellipse. So we're going to expand the area of view mapping. I was the first to think of the layout () method, because when the view's parent layout onlayout () calls the view's layout () for the Child view layout, I rewrote the layout method:

@Override public
void layout (int. left, int. top, int right, int 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, and that's the big one that expands the view to this maximum value.

When put a view in layout, the effect came out no problem, but I put multiple view to LinearLayout when found a few view overlap, oh seth. It dawned on me that the Nima layout had specified the height of the area I had drawn, and I forced myself to occupy another view. So, I should rewrite onmeasure () and tell my father layout how much I want to do when I measure the width of the height:

@Override
protected void onmeasure (int widthmeasurespec, int 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, to see the super.onmeasure measurement when the width of the big, the width is set to the maximum value. Tell the father layout how much I want the site, so when I draw the time I want to play how to play.

The implementation of Drawing view

OK, come to the key place, the front is all buttoned up to see how we draw a few circles of our circle. To draw circles is to rewrite the OnDraw () method.

First you need a brush:

Paint mpaint = new Paint ();
Mpaint.setantialias (TRUE);/anti-aliasing

Get the drawing area.

We can get to the drawing area through Getdrawingrect (Rect), and we can calculate the radius of the circle by drawing the area.

Rect bounds = new Rect ();

@Override
protected void OnDraw (Canvas Canvas) {
 getdrawingrect (bounds);//Get the bounds of view

 int size = Bounds.height () > Bounds.width ()? Bounds.width (): Bounds.height ();
 float Outerradius = SIZE/2; Calculate the radius of the drawn Circle
}

Draw a Fill circle

So we're going to use colorstatelist, where we do an initialization, and we support defining this attribute in XML:

The default transparent fill.
colorstatelist incirclecolors = colorstatelist.valueof (color.transparent);

private void Initialize (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 attribute request their own Google.

Draws the fill circle's color based on the click, Check, select State, because it is filled, so the paint style here is fill:

int circlecolor = Incirclecolors.getcolorforstate (getdrawablestate (), 0);
Mpaint.setstyle (Paint.Style.FILL);
Mpaint.setcolor (Circlecolor);
Canvas.drawcircle (Bounds.centerx (), Bounds.centery (), Outerradius-outlinewidth, mpaint);

The center of the Circle is the center of the drawing area, which is the radius of the area circle minus the width of the outer contour Circle Line. This just fills the circle and the outer contour circles do not overlap.

Draw Outer Border Circle

This is simple, because it is a hollow line, so style is stroke, and then the width of the line, the color of the brush:

Mpaint.setstyle (Paint.Style.STROKE);
Mpaint.setstrokewidth (outlinewidth);
Mpaint.setcolor (OutlineColor);
Canvas.drawcircle (Bounds.centerx (), Bounds.centery (), OUTERRADIUS-OUTLINEWIDTH/2, mpaint);

The center of the Circle is the center of the drawing area, and the radius is the radius of the area circle minus half the width of the outer contour circle, so that the external contour line and the inner fill circle are close to each other.

Draw a TextView word

For our drawing and textview our own drawing does not overlap, we kill super.ondraw (canvas), so here we have to write the TextView word.

First get TextView's default brush, set the TextView itself font color, anti-aliasing, in order to beautiful we forced the text center:

Reprint
Paint Paint = Getpaint ();
Paint.setcolor (Getcurrenttextcolor ());
Paint.setantialias (true);
Paint.settextalign (Paint.Align.CENTER);
float texty = Bounds.centery ()-(paint.descent () + paint.ascent ())/2;
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, style as stroke, sets the width of the line, and finally specifies the area and center of the drawing, and the angle:

RECTF marcrect = new RECTF ();
Rect bounds = new Rect ();

@Override
protected void OnDraw (Canvas Canvas) {
 getdrawingrect (bounds);//Get the bounds of the view
 ...

 Draws a progress bar arc.
 Mpaint.setcolor (progresslinecolor);
 Mpaint.setstyle (Paint.Style.STROKE);
 Mpaint.setstrokewidth (progresslinewidth);
 Mpaint.setstrokecap (Paint.Cap.ROUND);
 int deletewidth = progresslinewidth + outlinewidth;
 Specifies the drawing area
 marcrect.set (Bounds.left + DELETEWIDTH/2, Bounds.top + DELETEWIDTH/2,
 bounds.right-deletewidth/ 2, BOUNDS.BOTTOM-DELETEWIDTH/2);
 Canvas.drawarc (marcrect, 0, 360 * progress/100, False, mpaint);
}

Here is the difficulty in specifying the drawing area, because the external contour line can not be covered, so to be close to the external contour of the interior painting, so the outermost draw the circle of the region, so to subtract (the width of the outer circle and the progress line width)/2 The line is the boundary of the progress bar.

Complete code for drawing and measuring

Here is the key code has been finished, you can write a try yourself, I place the complete OnDraw () and Onmeasure () of the source code posted:

private int outlinecolor = Color.Black;
private int outlinewidth = 2;
Private Colorstatelist incirclecolors = colorstatelist.valueof (color.transparent);
private int circlecolor;
private int progresslinecolor = Color.Blue;
private int progresslinewidth = 8;
Private Paint Mpaint = new Paint ();
Private RECTF Marcrect = new RECTF ();
private int progress = 100;

Final Rect bounds = new Rect ();

 @Override protected void OnDraw (Canvas Canvas) {//Get the Border Getdrawingrect (bounds) of the view; int size = Bounds.height () > Bounds.width ()?
 Bounds.width (): Bounds.height ();

  float Outerradius = SIZE/2;
 Draw internal background int circlecolor = Incirclecolors.getcolorforstate (getdrawablestate (), 0);
 Mpaint.setstyle (Paint.Style.FILL);
 Mpaint.setcolor (Circlecolor);

 Canvas.drawcircle (Bounds.centerx (), Bounds.centery (), Outerradius-outlinewidth, mpaint);
 Draw a border round mpaint.setstyle (Paint.Style.STROKE);
 Mpaint.setstrokewidth (Outlinewidth);
 Mpaint.setcolor (OutlineColor); Canvas.drawcircle (Bounds.centerx (), boundS.centery (), OUTERRADIUS-OUTLINEWIDTH/2, mpaint);
 Reprint Paint Paint = Getpaint ();
 Paint.setcolor (Getcurrenttextcolor ());
 Paint.setantialias (TRUE);
 Paint.settextalign (Paint.Align.CENTER);
 float texty = Bounds.centery ()-(paint.descent () + paint.ascent ())/2;

 Canvas.drawtext (GetText (), toString (), Bounds.centerx (), texty, paint);
 Draw the progress bar Mpaint.setcolor (Progresslinecolor);
 Mpaint.setstyle (Paint.Style.STROKE);
 Mpaint.setstrokewidth (Progresslinewidth);
 Mpaint.setstrokecap (Paint.Cap.ROUND);
 int deletewidth = progresslinewidth + outlinewidth;  Marcrect.set (Bounds.left + DELETEWIDTH/2, Bounds.top + DELETEWIDTH/2, BOUNDS.RIGHT-DELETEWIDTH/2, Bounds.bottom-

 DELETEWIDTH/2);
Canvas.drawarc (marcrect, 0, 360 * progress/100, False, Mpaint); @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec, he
 IGHTMEASURESPEC);
 int linewidth = 4 * (outlinewidth + progresslinewidth); int width = getmeasuredwidth ();
 int height = getmeasuredheight ();
 int size = (Width > Height width:height) + linewidth;
Setmeasureddimension (size, size);

 }

Currently known fixes for compatibility issues
1. The current Circletextprogressbar in the Reletivelayot height will become larger, resulting in a little bit of the progress bar flat. The repair method is as follows:
If you want to use Circletextprogressbar in Reletivelayot, do not rewrite the Onmeasure () method, and then specify the width of the circletextprogressbar in XML, such as 50DP, And then there's no problem.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.