Android Custom view realizes water ripple progress ball effect _android

Source: Internet
Author: User
Tags getcolor int size

The view we're going to implement today doesn't have a lot of interactive view, so it inherits view.

Custom view routines, very deep

1, get our custom attribute Attrs (can be omitted)

2, rewrite the Onmeasure method, calculate the control width and height

3, rewrite the OnDraw method, draw our control

So the custom view's routines are clear.

Let's look at today's effect chart, one of which is slowing down (the length of time)


We follow the routines.

One. Custom Attributes

 <declare-styleable name= "Waveprogressview" >
  <attr name= "radius" format= "Dimension|reference"/>
  <attr name= "Radius_color" format= "color|reference"/> <attr name= "Progress_text_color"
  Color|reference "/> <attr name=" progress_text_size "format=" dimension|reference
  "/> <attr name=
  "Progress_color" format= "color|reference"/>
  <attr name= "Progress" format= "float"/> <attr name=
  "Maxprogress" format= "float"/>
 </declare-styleable>

Look at the effect chart and we know what attributes are needed. I will not say it.

And then we get these attributes, and that's what we use TypedArray to get them. Of course it is obtained in construction, generally we will make a copy of the construction method, fewer parameters call the argument more, and then go to the one with the most parameters.

TypedArray a = GetContext (). Obtainstyledattributes (Attrs, R.styleable.waveprogressview, Defstyleattr, R.style.waveprogressviewdefault);
  RADIUS = (int) a.getdimension (R.styleable.waveprogressview_radius, radius);
  TextColor = A.getcolor (r.styleable.waveprogressview_progress_text_color, 0);
  Textsize = a.getdimensionpixelsize (r.styleable.waveprogressview_progress_text_size, 0);
  Progresscolor = A.getcolor (r.styleable.waveprogressview_progress_color, 0);
  Radiuscolor = A.getcolor (r.styleable.waveprogressview_radius_color, 0);
  progress = a.getfloat (r.styleable.waveprogressview_progress, 0);
  maxprogress = A.getfloat (r.styleable.waveprogressview_maxprogress, MB);
  A.recycle ();

Note: R.style.waveprogressviewdefault is the default style for this control.

Two. Onmeasure Measurement

The main way we rewrite this method is to set our own width and height by seeing the width and height of the parent.

 @Override 
 protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
  //compute width and height
  int exceptw = Getpaddingleft () + getpaddingright () + 2 * RADIUS;
  int excepth = getpaddingtop () + getpaddingbottom () + 2 * RADIUS;
  int width = resolvesize (EXCEPTW, widthmeasurespec);
  int height = resolvesize (excepth, heightmeasurespec);
  int min = math.min (width, height);

  This.width = this.height = min;

  Calculate the radius, minus the minimum value of padding
  int minlr = Math.min (Getpaddingleft (), Getpaddingright ());
  int mintb = Math.min (Getpaddingtop (), Getpaddingbottom ());
  minpadding = Math.min (MINLR, MINTB);
  RADIUS = (min-minpadding * 2)/2;

  Setmeasureddimension (min, min);
 

First, the width and height of the control must be the same, because it is a circle. In fact, the width and height of the radius and the inner margin, here in the margin, we take up and down the smallest one. The width and height are also selected to take the smallest.

this.width = this.height = min; Contains the left and right margins.

resolveSizeThis method is very good for us to achieve the width and height I want to slow down the source code.

 public static int resolvesizeandstate (int size, int measurespec, int childmeasuredstate) {
  final int specmode = Measur Espec.getmode (MEASURESPEC);
  Final int specsize = Measurespec.getsize (measurespec);
  final int result;
  Switch (specmode) {case
   measurespec.at_most:
    if (specsize < size) {result
     = Specsize | Measured_state_too_small;
    } else {result
     = size;
    }
    break;
   Case measurespec.exactly: Result
    = specsize;
    break;
   Case measurespec.unspecified:
   default: Result
    = size;
  }
  return Result | (Childmeasuredstate & Measured_state_mask);
 }

If we write the same way.

Finally by setMeasuredDimension setting width and height.

Three. OnDraw Drawing

There are a lot of APIs available on the drawing and there's not much to say here.

Drawing first is the initialization of some brushes.

You need to mention that the brush to draw the path path is set to the PorterDuff.Mode.SRC_IN pattern, which displays only the overlapping parts.

 Pathpaint = new Paint (paint.anti_alias_flag);
  Pathpaint.setcolor (Progresscolor);
  Pathpaint.setdither (true);
  Pathpaint.setxfermode (New Porterduffxfermode (PorterDuff.Mode.SRC_IN));

We're going to draw all the drawing to a transparent bitmap , and then draw this bitmap onto the canvas.

if (bitmap = = null) {
   bitmap = Bitmap.createbitmap (This.width, This.height, Bitmap.Config.ARGB_8888);
   Bitmapcanvas = new Canvas (bitmap);
  }

To facilitate computation and rendering, I translate the coordinate system to padding a distance

 Bitmapcanvas.save ();
  Mobile coordinate system
  bitmapcanvas.translate (minpadding, minpadding);
 .... Some thing
 bitmapcanvas.restore ();

3.1 Draw a circle

  Bitmapcanvas.drawcircle (RADIUS, radius, radius, circlepaint);

3.2 To draw the path path.

One is to achieve the ripple around the float, and up and down the amplitude slowly reduced

Before drawing this we need to know the general principle of the Hill Bessel curve.

To put it simply is to know: P1 starting point, P2 is the endpoint, P1 is the control point. Using the formula of the Searle curve, we can get some points along the way, and finally connect the dots.

The following image comes to the network:


Hill Bessel Curve

Provides a functional method for plotting Bezier curves in android-sdk rQuadTo

public void Rquadto (float dx1, float dy1, float dx2, float dy2)

DX1: Control point x Coordinate, which represents the displacement coordinate relative to the last endpoint x coordinate, can be negative, positive value is added, negative value is subtracted;

Dy1: The y-coordinate of the control point, the displacement coordinate relative to the last endpoint y coordinate. The same can be negative, positive values are added, negative values are subtracted;

DX2: End x coordinates, also a relative coordinate, relative to the last endpoint x coordinates of the displacement value, can be negative, positive to add, negative value to subtract;

Dy2: The end y coordinate, also a relative, the displacement value relative to the last endpoint y coordinate. can be negative, positive values are added, negative values are subtracted;

These four parameters are all passed relative values, relative to the last endpoint of the displacement value.

To achieve a gradual decrease in amplitude we can adjust the y-coordinate of the control point, namely:

float percent=progress * 1.0f/maxprogress;

You can get the [0,1]

A closed range, [0,1] This goods good, I like, can come to do a lot of things.

So we can adjust the percent y-coordinate of the control point according to.

Count the number of Bezier curves drawn based on the diameter
   int count = radius * 4/60;
   The coordinate of control-control point y
   (1-percent) *;
   for (int i = 0; i < count; i++) {
    path.rquadto (-point, 0);
    Path.rquadto (point, 0);
   }

To achieve the left and right ripple only need to control the closed path in the upper left corner of the X coordinate can, of course, is also based on it percent .

We can combine the following figure to understand the above words.

Path draws a complete code fragment.

 Draw path
  //Reset Drawing route
  path.reset ();
  float percent=progress * 1.0f/maxprogress;
  Float y = (1-percent) * radius * 2;
  Move to top right
  path.moveto (RADIUS * 2, y);
  Move to the bottom right
  path.lineto (RADIUS * 2, RADIUS * 2);
  Move to the leftmost bottom
  path.lineto (0, RADIUS * 2);
  Move to top left
  //Path.lineto (0, y);
  To achieve the left and right fluctuations, according to progress to translate
  Path.lineto (-(1-percent) * radius*2, y);
  if (Progress!= 0.0f) {
   //number of times the Bezier curve is plotted based on the diameter
   int count = radius * 4/60;
   The coordinate of control-control point y
   (1-percent) *;
   for (int i = 0; i < count; i++) {
    path.rquadto (-point, 0);
    Path.rquadto (point, 0);
   }
  Closed
  path.close ();
  Bitmapcanvas.drawpath (path, pathpaint);

3.3 Text to draw progress

This is relatively simple, drawn in the middle of the control can be. The coordinate calculation of the text is very well understood.

 Draws
  the literal String text = progress + "%";
  float TEXTW = textpaint.measuretext (text);
  Paint.fontmetrics FontMetrics = Textpaint.getfontmetrics ();
  Float BaseLine = Radius-(fontmetrics.ascent + fontmetrics.descent)/2;
  Bitmapcanvas.drawtext (text, RADIUS-TEXTW/2, BaseLine, Textpaint);

Finally, don't forget to draw our bitmap drawings onto the canvas.

Canvas.drawbitmap (bitmap, 0, 0, NULL);

Well, finally, it's a practical method, where we don't have to Thread+handler, we use attribute animation.

You know!!! , like

 Objectanimator objectAnimator0 = objectanimator.offloat (Waveprogressview_0, "Progress", 0f, 100f);
  Objectanimator0.setduration (3300);
  Objectanimator0.setinterpolator (New Linearinterpolator ());
  Objectanimator0.start ();

Conclusion

So far, we have achieved our results. This is the full content of this article, I hope the content of this article for everyone to develop Android can help.

Related Article

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.