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.
resolveSize
This 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.