Let's take a look at the effect chart.
Beat the ball to do this animation, need to master:
1. Property Animation
2, Path class, Canvas class
3. Bezier curve
4. Surfaceview Usage
5. Custom attr Properties
6. Architecture: State mode, controller
7, Free fall, parabola and other concepts
No more, just the code.
1.dancingview.java
public class Dancingview extends Surfaceview implements Surfaceholder.callback {public static final int state_down =
1;//down state public static final int state_up = 2;//up state public static final int default_point_radius = 10;
public static final int default_ball_radius = 13;
public static final int default_line_width = 200;
public static final int default_line_height = 2;
public static final int default_line_color = Color.parsecolor ("#FF9800");
public static final int default_point_color = Color.parsecolor ("#9C27B0");
public static final int default_ball_color = Color.parsecolor ("#FF4081"); public static final int default_down_duration = 600;//ms public static final int default_up_duration = 600;//ms Public static final int default_freedown_duration = 1000;//ms public static final int max_offset_y = 50;//horizontal Drop max offset Distance publ IC int ponit_radius = default_point_radius;//ball radius public int Ball_radius = default_ball_radius;//Ball radius private Paint m
Paint; Private Path MPath;
private int mlinecolor;
private int mponitcolor;
private int mballcolor;
private int mlinewidth;
private int mlineheight;
private float mdowndistance;
private float mupdistance;
private float freeballdistance; Private Valueanimator mdowncontroller;//Drop controller Private valueanimator mupcontroller;//Upper missile controller private Valueanimator Mfreed
owncontroller;//Free Fall Controller private Animatorset Animatorset;
private int state;
Private Boolean ismupcontrollerdied = false;
Private Boolean isanimationshowing = false;
Private Boolean isbounced = false;
Private Boolean isballfreeup = false;
Public Dancingview {Super (context);
Init (context, NULL);
Public Dancingview (context, AttributeSet attrs) {Super (context, attrs);
Init (context, attrs);
Public Dancingview (context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr);
Init (context, attrs); } private void Init (Context context, AttributeSet attrs) {initattributes (context, attrs);
Mpaint = new Paint ();
Mpaint.setantialias (TRUE);
Mpaint.setstrokewidth (Mlineheight);
Mpaint.setstrokecap (Paint.Cap.ROUND);
MPath = new Path ();
Getholder (). Addcallback (this);
Initcontroller (); } private void Initattributes (context context, AttributeSet attrs) {TypedArray Typearray = Context.obtainstyledatt
Ributes (Attrs, R.styleable.dancingview);
Mlinecolor = Typearray.getcolor (R.styleable.dancingview_linecolor, Default_line_color);
Mlinewidth = Typearray.getdimensionpixeloffset (R.styleable.dancingview_linewidth, DEFAULT_LINE_WIDTH);
Mlineheight = Typearray.getdimensionpixeloffset (R.styleable.dancingview_lineheight, DEFAULT_LINE_HEIGHT);
Mponitcolor = Typearray.getcolor (R.styleable.dancingview_pointcolor, Default_point_color);
Mballcolor = Typearray.getcolor (R.styleable.dancingview_ballcolor, Default_ball_color);
Typearray.recycle (); } Private VOID Initcontroller () {Mdowncontroller = valueanimator.offloat (0, 1);
Mdowncontroller.setduration (default_down_duration);
Mdowncontroller.setinterpolator (New Decelerateinterpolator ()); Mdowncontroller.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void Onanimati
OnUpdate (Valueanimator animation) {mdowndistance = max_offset_y * (float) animation.getanimatedvalue ();
Postinvalidate ();
}
}); Mdowncontroller.addlistener (New Animator.animatorlistener () {@Override public void Onanimationstart (animator
Animation) {state = State_down; @Override public void Onanimationend (animator animation) {} @Override public void Onani
Mationcancel (animator animation) {} @Override public void Onanimationrepeat (animator animation) {
}
});
Mupcontroller = valueanimator.offloat (0, 1); Mupcontroller.setduration (Default_up_durATION);
Mupcontroller.setinterpolator (New Dancinginterpolator ()); Mupcontroller.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void onanimation
Update (Valueanimator animation) {mupdistance = max_offset_y * (float) animation.getanimatedvalue ();
if (mupdistance >= max_offset_y) {//Enter freefall state isbounced = true; if (!mfreedowncontroller.isrunning () &&!mfreedowncontroller.isstarted () &&!isballfreeup) {m
Freedowncontroller.start ();
} postinvalidate ();
}
}); Mupcontroller.addlistener (New Animator.animatorlistener () {@Override public void Onanimationstart (animator
Imation) {state = STATE_UP;
@Override public void Onanimationend (animator animation) {ismupcontrollerdied = true;
@Override public void Onanimationcancel (animator animation) {} @Override public void Onanimationrepeat (animator animation) {}});
Mfreedowncontroller = valueanimator.offloat (0, 8f);
Mfreedowncontroller.setduration (default_freedown_duration);
Mfreedowncontroller.setinterpolator (New Decelerateinterpolator ()); Mfreedowncontroller.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void Onani
Mationupdate (Valueanimator animation) {//The formula solves the rising deceleration and descent acceleration float t = (float) animation.getanimatedvalue ();
freeballdistance = * T-5 * t * t;
if (ismupcontrollerdied) {//up-throw, to Critical point postinvalidate ();
}
}
}); Mfreedowncontroller.addlistener (New Animator.animatorlistener () {@Override public void Onanimationstart (Anima
Tor animation) {isballfreeup = true;
@Override public void Onanimationend (animator animation) {isanimationshowing = false; Cycle the second time startanimationS (); @Override public void Onanimationcancel (animator animation) {} @Override public void on
Animationrepeat (animator animation) {}});
Animatorset = new Animatorset ();
Animatorset.play (Mdowncontroller). before (Mupcontroller); Animatorset.addlistener (New Animator.animatorlistener () {@Override public void Onanimationstart (animator Anim
ation) {isanimationshowing = true; @Override public void Onanimationend (animator animation) {} @Override public void Onani
Mationcancel (animator animation) {} @Override public void Onanimationrepeat (animator animation) {
}
});
/** * Start animation, external call */public void startanimations () {if (isanimationshowing) {return;
} if (Animatorset.isrunning ()) {animatorset.end ();
Animatorset.cancel ();
} isbounced = false;
Isballfreeup = false; Ismupcontrollerdied = false;
Animatorset.start ();
} @Override protected void OnDraw (Canvas Canvas) {Super.ondraw (Canvas);
A rope is composed of the Hill Bessel curve of the left and right two parts mpaint.setcolor (Mlinecolor);
Mpath.reset ();
Starting point Mpath.moveto (GetWidth ()/2-MLINEWIDTH/2, GetHeight ()/2); if (state = = State_down) {//drop/************** Draw rope start *************///left part of Bezier mpath.quadto (float) (GETW Idth ()/2-MLINEWIDTH/2 + mlinewidth * 0.375), getheight ()/2 + mdowndistance, getwidth ()/2, getheight ()
/2 + mdowndistance); The right part of the Bezier Mpath.quadto (float) (getwidth ()/2 + MLINEWIDTH/2-mlinewidth * 0.375), getheight ()/2 + Mdowndista
NCE, GetWidth ()/2 + MLINEWIDTH/2, getheight ()/2);
Mpaint.setstyle (Paint.Style.STROKE);
Canvas.drawpath (MPath, mpaint);
/************** draws the rope end *************//************** draws the bouncing ball to begin *************/Mpaint.setstyle (Paint.Style.FILL);
Mpaint.setcolor (Mballcolor); CaNvas.drawcircle (GetWidth ()/2, GetHeight ()/2 + Mdowndistance-ball_radius, Ball_radius, Mpaint);
/************** draw a bouncing ball end *************/} else if (state = = STATE_UP) {//Up arrow/************** draw rope start *************/ The left part of the Bezier Mpath.quadto (float) (getwidth ()/2-MLINEWIDTH/2 + mlinewidth * 0.375), getheight ()/2 + 50-
Mupdistance, GetWidth ()/2, GetHeight ()/2 + (50-mupdistance)); The right part of the Bezier Mpath.quadto (float) (getwidth ()/2 + MLINEWIDTH/2-mlinewidth * 0.375), getheight ()/2 + 50-mupdis
Tance, GetWidth ()/2 + MLINEWIDTH/2, getheight ()/2);
Mpaint.setstyle (Paint.Style.STROKE);
Canvas.drawpath (MPath, mpaint);
/************** Draw rope over *************/Mpaint.setstyle (Paint.Style.FILL);
Mpaint.setcolor (Mballcolor); Elastic ball, Free fall if (!isbounced) {//Ascent Canvas.drawcircle (GetWidth ()/2, GetHeight ()/2 + (max_offset_y -mupdistance)-Ball_rAdius, Ball_radius, Mpaint); else {//Free fall Canvas.drawcircle (GetWidth ()/2, getheight ()/2-freeballdistance-ball_radius, Ball_r
Adius, Mpaint);
} mpaint.setcolor (Mponitcolor);
Mpaint.setstyle (Paint.Style.FILL);
Canvas.drawcircle (GetWidth ()/2-MLINEWIDTH/2, GetHeight ()/2, Ponit_radius, mpaint);
Canvas.drawcircle (GetWidth ()/2 + MLINEWIDTH/2, getheight ()/2, Ponit_radius, mpaint); @Override public void surfacecreated (Surfaceholder holder) {Canvas Canvas = Holder.lockcanvas ();/Lock Entire SURFACEV
Iew object to get the canvas on the surface.
Draw (canvas); Holder.unlockcanvasandpost (Canvas)//free canvas, submit modification} @Override public void surfacechanged (Surfaceholder holder, int for Mat, int width, int height) {} @Override public void surfacedestroyed (Surfaceholder holder) {}}
2.dancinginterpolator.java
public class Dancinginterpolator implements Interpolator {
@Override public
float getinterpolation (float input ) {return
(float) (1-math.exp ( -3 * input) * MATH.COS (* input));
}
3. Custom Attribute Styles.xml
<declare-styleable name= "Dancingview" >
<attr name= "linewidth" format= "Dimension"/>
<attr Name= "Lineheight" format= "Dimension"/> <attr name=
"Pointcolor" format= "Reference|color"/>
< attr name= "LineColor" format= "Reference|color"/> <attr name= "
ballcolor" format= "Reference|color"/>
</declare-styleable>
Note: color, size, parameters can be tested on their own, adjusted.
The above is the entire content of this article, I hope for everyone's study and work can help Oh.