I saw an iOS component Pendulumview on the Internet, which realized the animation effect of the pendulum. Because the native progress bar does not look good, you can customize the view to achieve this effect, and later can be used to load the page's progress bar.
No more nonsense, first.
The bottom black Edge is recorded accidentally recorded, can be ignored.
Since it's a custom view, we'll follow the standard process, the first step, custom attribute custom properties
Creating a Property file
Create a new Attrs.xml file in the Res->values directory of your Android project with the following file contents:
[HTML] View plain copy
<?xml version= "1.0" encoding= "Utf-8"?>
<resources>
<declare-styleable name= "Pendulumview" >
<attr name= "Globenum" format= "integer"/>
<attr name= "Globecolor" format= "Color"/>
<attr name= "Globeradius" format= "Dimension"/>
<attr name= "Swingradius" format= "Dimension"/>
</declare-styleable>
</resources>
Where Declare-styleable's Name property is used to reference the property file in code. The Name property, in general, is the class name of our custom view, which is more intuitive.
Using Styleale, the system can do many constants (int[] arrays, subscript constants) and so on, to simplify our development work, such as the following code in the use of r.styleable.pendulumview_golbenum and so on is the system for our automatic generation.
The Globenum property represents the number of small balls, Globecolor represents the ball color, Globeradius represents the sphere radius, and the Swingradius represents the swing Radius Read property value
Reading a property value through Typedarray in a custom view's construction method can also get the property value through AttributeSet, but if the property value is a reference type, then only the ID is obtained, and the real property value is still to be obtained by resolving the ID. And Typedarray directly helped us to complete the above work.
[Java] View plain copy
Public Pendulumview (context context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr);
To read a custom property value using Typedarray
TypedArray ta = context.getresources (). Obtainattributes (Attrs, r.styleable.pendulumview); int count = Ta.getindexcount ();
for (int i = 0; i < count; i++) {
int attr = Ta.getindex (i);
Switch (attr) {
Case R.styleable.pendulumview_globenum:
Mglobenum = Ta.getint (attr, 5);
Break
Case R.styleable.pendulumview_globeradius:
Mgloberadius = Ta.getdimensionpixelsize (attr, (int) typedvalue.applydimension (typedvalue.complex_unit_px, 16, Getresources (). Getdisplaymetrics ());
Case R.styleable.pendulumview_globecolor:
Mglobecolor = Ta.getcolor (attr, Color.Blue);
Case R.styleable.pendulumview_swingradius:
Mswingradius = Ta.getdimensionpixelsize (attr, (int) typedvalue.applydimension (typedvalue.complex_unit_px, 16, Getresources (). Getdisplaymetrics ());
}
}
Ta.recycle (); Avoid problems the next time you read
Mpaint = new Paint ();
Mpaint.setcolor (Mglobecolor);
}
Overriding the Onmeasure () method
[Java] View plain copy
@Override
protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec, HEIGHTMEASURESPEC); int widthmode = Measurespec.getmode (widthmeasurespec); int widthsize = Measurespec.getsize ( WIDTHMEASURESPEC); int heightmode = Measurespec.getmode (heightmeasurespec); int heightsize = Measurespec.getsize ( HEIGHTMEASURESPEC);//height for ball radius + swing radius
int height = Mgloberadius + mswingradius;//width = Swing radius + (number of balls-1) * Ball diameter int width = Mswingradius + Mgloberadius * 2 * (mglobenum -1) + mswingradius;//If the measurement mode is exactly, use the recommended value directly, such as not for exactly (general handling wrap_content case), use your own calculated width-height setmeasureddimension ( Widthmode = = measurespec.exactly)? Widthsize:width, (Heightmode = = measurespec.exactly)? Heightsize:height);}
which
[Java] View plain copy
int height = Mgloberadius + mswingradius;<pre name= "code" class= "java" >int width = Mswingradius + Mgloberadius * 2 * (mGlobeNum-1) + Mswingradius; used to process the measurement mode for the At_most, generally the width of the custom view setting in order to wrap_content, at this time through the number of small balls, radius, swing radius, etc. to calculate the width of the view, such as:
Take the number of balls 5 as an example, the size of the view is red rectangular region rewrite OnDraw () method
650) this.width=650; "Src=" Http://s4.51cto.com/wyfs02/M00/87/53/wKiom1fc6TiB4XeRAAAQZR33f_8699.png-wh_500x0-wm_3 -wmp_4-s_3577198470.png "title=" 1.png "alt=" Wkiom1fc6tib4xeraaaqzr33f_8699.png-wh_50 "/>
[Java] View plain copy
@Override
protected void OnDraw (canvas canvas) {
Super.ondraw (canvas);
Draw other balls except the left and right two balls
for (int i = 0; i < mGlobeNum-2; i++) {canvas.drawcircle (Mswingradius + (i + 1) * 2 * Mgloberadius, Mswingradius, mGl Oberadius, mpaint);}
if (Mleftpoint = = NULL | | mrightpoint = = NULL) {//Initialize the most left and right ball coordinates
Mleftpoint = new Point (Mswingradius, mswingradius); mrightpoint = new Point (Mswingradius + Mgloberadius * 2 * (Mglobenum- 1), Mswingradius);//Start Swinging animation
Startpendulumanimation ();
}
Draw left and right balls
Canvas.drawcircle (Mleftpoint.x, Mleftpoint.y, Mgloberadius, Mpaint); Canvas.drawcircle (MRightPoint.x, MRightPoint.y , Mgloberadius, mpaint);}
The OnDraw () method is the key to customizing view, where the view is drawn in the body of the method. The code first draws a small ball other than the left-most-right ball, and then judges the coordinate values of the two spheres, if it is the first draw and the coordinate value is empty, the two spherical coordinates are initialized and the animation is turned on. Finally, by mleftpoint,mrightpoint the x, Y value, draw left and right two balls.
Where Mleftpoint,mrightpoint are Android.graphics.Point objects, they are used only to store the x, Y coordinate information of the left and right balls.
Using Property animations
[Java] View plain copy
public void Startpendulumanimation () {
Using Property animations
Final Valueanimator anim = Valueanimator.ofobject (new Typeevaluator () {@Override
Public Object evaluate (float fraction, object Startvalue, Object Endvalue) {//Parameter fraction is used to indicate the completion of the animation, We calculate the current animation value based on it double angle = math.toradians (fraction); int x = (int) ((mswingradius-mgloberadius) * Math.sin (angle)) ; int y = (int) ((mswingradius-mgloberadius) * Math.Cos (angle)); Point point = new Point (x, y);
return point;
}
}, New Point (), New Point ());
Anim.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override
public void Onanimationupdate (Valueanimator animation) {Point point = (point) animation.getanimatedvalue ();// Get the current fraction value
float fraction = anim.getanimatedfraction ();//Determine whether the fraction is first reduced and then increased, that is, whether it is in the upward swing state//In each of the upward swing when the ball is switched
if (lastslope && fraction > mlastfraction) {isnext =!isnext;
}
By constantly changing the left and right ball of x, Y coordinate value to achieve the animation effect//Use Isnext to determine whether the left small ball motion, or the isnext of the ball if (a) {
When the left ball swings, the right ball is placed in the initial position
Mrightpoint.x = Mswingradius + Mgloberadius * 2 * (mGlobeNum-1); mrightpoint.y = Mswingradius;
Mleftpoint.x = Mswingradius-point.x;
Mleftpoint.y = Mgloberadius + point.y;
} else {
When the right ball swings, the left ball is placed in the initial position
Mleftpoint.x = Mswingradius;
Mrightpoint.y = Mswingradius;
Mrightpoint.x = Mswingradius + (mGlobeNum-1) * Mgloberadius * 2 + point.x;mrightpoint.y = Mgloberadius + point.y;
}
Invalidate ();
Lastslope = fraction < mlastfraction;
Mlastfraction = fraction;
}
});
Set Perpetual loop Playback
Anim.setrepeatcount (valueanimator.infinite);//set cycle mode to play in reverse order
Anim.setrepeatmode (Valueanimator.reverse); anim.setduration (200);
Set up the tween to control the rate at which the animation changes
Anim.setinterpolator (New Decelerateinterpolator ()); Anim.start ();
}
The Valueanimator.ofobject method is used so that the point object can be manipulated and more visually specific. There is also the use of the Ofobject method of the custom Typeevaluator object, resulting in a fraction value, which is a decimal number changed from 0-1. Therefore, the latter two parameters of the method Startvalue (new Point ()), Endvalue () is not meaningful, or can directly not write, here is written mainly for the sake of understanding. The same can be obtained directly using the Valueanimator.offloat (0f, 1f) method to obtain a fractional change from 0-1.
[Java] View plain copy
Final Valueanimator anim = Valueanimator.ofobject (new Typeevaluator () {@Override
Public Object evaluate (float fraction, object Startvalue, Object Endvalue) {//Parameter fraction is used to indicate the completion of the animation, We calculate the current animation value based on it double angle = math.toradians (fraction); int x = (int) ((mswingradius-mgloberadius) * Math.sin (angle)) ; int y = (int) ((mswingradius-mgloberadius) * Math.Cos (angle)); Point point = new Point (x, y);
return point;
}
}, New Point (), New Point ());
by fraction, we calculate the angular change value when the ball swings, and the value represented by the 0-90 degree Mswingradius-mgloberadius is the length of the Green Line in the figure, the direction of the swing, The path of the center of the ball is an arc with a radius of (Mswingradius-mgloberadius), with a change of x value (Mswingradius-mgloberadius) *sin (angle), The Change y value is (mswingradius-mgloberadius) *cos (angle) corresponds to the ball of the actual center coordinates of (mswingradius-x,mgloberadius+y) The right ball motion is similar to the left, only the direction is different. The right ball is the actual center coordinate (Mswingradius + (mGlobeNum-1) * Mgloberadius * 2 + x,mgloberadius+y) visible on both sides of the ball's ordinate is the same, only the horizontal axis is different.
[Java] View plain copy
float fraction = anim.getanimatedfraction ();//Determine whether the fraction is first reduced and then increased, that is, whether it is in the upward swing state//In each of the upward swing when the ball is switched
if (lastslope && fraction > mlastfraction) {isnext =!isnext;
}
Record whether the last fraction has been reduced
[Java] View plain copy
Lastslope = fraction < mlastfraction;
Record the last fraction
Mlastfraction = fraction;
These two pieces of code is used to calculate when to switch the motion of the ball, the animation set the loop playback, and the loop mode for the reverse play, so the animation of a period of the ball is thrown together with the small ball falling process. In this procedure, the value of fraction is first 0 to 1, and then 1 to 0. So when is the beginning of a new cycle of animation? is in the small ball is about to throw up, at this time to switch the ball, you can achieve the left side of the ball drop after the right ball thrown up, the right ball fell after the left small ball cast animation effect.
So how do you capture this point in time?
The fraction value increases continuously when the ball is thrown, and the fraction value decreases when the ball falls. The moment the ball is about to be thrown is the moment when the fraction from diminishing to increasing. The code records whether the last fraction is decreasing, and then compares whether this time the fraction is increasing, if two conditions are set up to switch the ball of motion.
[Java] View plain copy
Anim.setduration (200);
Set up the tween to control the rate at which the animation changes
Anim.setinterpolator (New Decelerateinterpolator ()); Anim.start ();
Set the duration of the animation to 200 milliseconds, the reader can change the value to achieve the purpose of modifying the ball swing speed.
Set the animation of the tween, because the ball is thrown is a gradual deceleration of the process, falling is a gradual acceleration of the process, so use decelerateinterpolator to achieve deceleration effect, in reverse play for the acceleration effect.
This article is from the "12063979" blog, please be sure to keep this source http://12073979.blog.51cto.com/12063979/1853371
Custom View implementation Pendulum effect progress bar Pendulumview