Custom View implementation Pendulum effect progress bar Pendulumview

Source: Internet
Author: User

Reprint Please specify source: http://blog.csdn.net/fightlei/article/details/52556755


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, the 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:

<?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


Reading property values


Reading property values through Typedarray in a custom view construction method

通过AttributeSet同样可以获取属性值,但是如果属性值是引用类型,则得到的只是ID,仍需继续通过解析ID获取真正的属性值,而TypedArray直接帮助我们完成了上述工作。

Public Pendulumview (context context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr); Use TypedArray to read custom property values TypedArray ta = context.getresources (). Obtainattributes (Attrs, R.STYLEABLE.PENDULUMVI        EW);        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) typedval                    Ue.applydimension (typedvalue.complex_unit_px, +, Getresources (). Getdisplaymetrics ()));                Break                    Case R.styleable.pendulumview_globecolor:mglobecolor = Ta.getcolor (attr, Color.Blue);                Break                Case R.styleable.pendulumview_swingradius:    Mswingradius = Ta.getdimensionpixelsize (attr, (int) typedvalue.applydimension (typedvalue.complex_unit_px, 16,                    Getresources (). Getdisplaymetrics ());            Break  }} ta.recycle ();        Avoid problems the next time you read Mpaint = new Paint ();    Mpaint.setcolor (Mglobecolor); }



Overriding the Onmeasure () method


@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 is ball radius + swing radius        int height = Mgloberadius + Mswingradius;        Width of the 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 values directly, such as exactly (general handling wrap_content case), using your own calculated width-height        setmeasureddimension (widthmode = measurespec.exactly)? Widthsize:width, (Heightmode = = measurespec.exactly)? heightsize:height);    }
which
int height = Mgloberadius + mswingradius;<pre name= "code" class= "java" >int width = Mswingradius + Mgloberadius * 2 * (mGlobeNum-1) + Mswingradius;

Used to deal with the at_most of the measurement mode, it is generally a custom view of the wide-height 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 For example, the size of the view is a red rectangular region

Overriding the OnDraw () method

@Override    protected void OnDraw (canvas canvas) {        super.ondraw (canvas);        Draw other balls for        (int i = 0; i < mGlobeNum-2; i++) {            canvas.drawcircle (Mswingradius + (i + 1) * 2 * Mglo except left and right two balls) Beradius, Mswingradius, Mgloberadius, mpaint);        }        if (Mleftpoint = = NULL | | mrightpoint = = NULL) {            //Initialize the left and right ball coordinates            mleftpoint = new Point (Mswingradius, Mswingradius);            mrightpoint = new Point (Mswingradius + Mgloberadius * 2 * (mGlobeNum-1), Mswingradius);            Turn on the oscillating animation            startpendulumanimation ();        }        Draw left and right two small spheres        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


public void Startpendulumanimation () {//Use property animation final Valueanimator Anim = valueanimator.ofobject (New Typeev                Aluator () {@Override public object evaluate (float fraction, object Startvalue, Object Endvalue) {                The parameter fraction is used to represent the completion of the animation, and 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 Onanimatio                Nupdate (Valueanimator animation) {Point point = (point) animation.getanimatedvalue ();                Gets the current fraction value of float fraction = anim.getanimatedfraction (); Determine if the fraction is first reduced and then increasedLarge, that is, whether it is in the upward swing state//In the swing up each time to switch the ball 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 ball motion, or  if (Isnext) {  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 the perpetual loop playback anim.setrepeatcount (valueanimator.infinite);        Set cycle mode to play Anim.setrepeatmode (Valueanimator.reverse) in reverse order;        Anim.setduration (200);        Set up the tween to control the change rate of the animation 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.
        Final Valueanimator anim = Valueanimator.ofobject (new Typeevaluator () {            @Override public            Object Evaluate (float Fraction, Object Startvalue, Object Endvalue) {                //parameter fraction is used to represent the completion of the animation, and 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, 0-90 degrees.


The value represented by Mswingradius-mgloberadius is the length of the Green Line in the figure, the direction of the swing, and the path of the center of the ball is an arc with a radius of (Mswingradius-mgloberadius). The change x value is (Mswingradius-mgloberadius) *sin (angle), the change Y value is (mswingradius-mgloberadius) *cos (angle)

The actual center coordinate of the corresponding ball is (mswingradius-x,mgloberadius+y)

The right-hand ball movement is similar to the left, only in a different direction. Right Ball actual Center coordinate (Mswingradius + (mGlobeNum-1) * Mgloberadius * 2 + x,mgloberadius+y)

Visible on the left and right side of the ball ordinate is the same, only the horizontal axis is different.

                float fraction = anim.getanimatedfraction ();                Determine if the fraction first decreases and then increases, that is, whether it is in the upward-swinging state                //to toggle the ball                if (lastslope && fraction > Mlastfraction) Each time it is about to swing upward                    isnext =!isnext;                }                Record whether the last fraction has been reduced
                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.

        Anim.setduration ($);        Set up the tween to control the change rate of the animation        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.

Start the animation, the pendulum effect of the custom view progress bar is implemented! Run quickly and see the effect!


If there is any mistake, please haihan.

Custom View implementation Pendulum effect progress bar Pendulumview

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.