First: The code is given later in the article:
Students who do not understand the Seibel curve can look at this article first: http://blog.csdn.net/u010335298/article/details/51912118
Two times the curve equations are explained and the control points are calculated according to the Seibel curve starting point, the end point and the line points:
The formula for the two-time Bell curve is:
Among them, P0 is the starting point, P1 is the control point, P2 is the end point, very good description of their relationship:
By the formula, we can find the coordinates of any point on the curve:
Assuming P0 (x, y), p1 (x, y), p2 (x, y) are known, the point we require is P (x, y), unknown, then:
x = (1-t) * (1-t) * p0.x + 2 * t * (1-t) * p1.x + t * t * p2.x;
y = (1-t) * (1-t) * P0.Y + 2 * t * (1-t) * p1.y + t * t * P2.Y;
Now let's assume that P0 (x, y), p (x, y), p2 (x, y) are known, how do we ask for P1 (x, y)? Just change the formula above and you can:
p1x = (p.x-(1-T) * (1-t) * p0.x-t * t * p2.x)/(2 * t * (1-T))
p1y = (P.Y-(1-T) * (1-t) * p0.y-t * t * p2.y)/(2 * t * (1-T))
The path of Android draws the bell curve:
The function for Android to draw the two-time bell curve is path. Quadto (P1.X,P1.Y,P2.X,P2.Y), where P1 is the control point, P2 is the end point
Use the Bitmapshader of the Android brush to make the drawing curve show the picture of the rope:
By setting the shader for the brush paint, if it is a bitmapshader, the brush will draw the picture as a background when drawing the path and various shapes.
In layman's words, we can choose a color for the brush so that when a line is drawn, the line is this color, similar to the background color
So let's choose a bitmapshader for the brush so that when we draw a line, the graph is displayed on the line, similar to the background image.
Specific can search the Internet to see.
Bitmapshader = new Bitmapshader (bitmap,shader.tilemode.mirror,shader.tilemode.repeat);
Mpaint.setshader (Bitmapshader);
So, when we draw the curve, we take the picture of the rope, as if we had drawn a rope.
Drag to change the implementation of the shape of the match Bell curve:
We need to drag Andy, change the appearance of the Rope (curve), because the position of Andy is also a point of the curve, we know the beginning and end of the curve, from the face of the curve of the explanation, we can find the position of the control point. In this way, the finger keeps changing position, the position of the control point is constantly changing, we just need to redraw the curve when the position of the finger changes.
Andy's launch animation and string rebound:
This is about the launch animation, which I designed:
The point of the curve convex (or concave down), and the point in the middle of the starting point and the end point are connected into a straight line, according to the linear equation, we can obtain the intersection of the line and the screen boundary, and then move along this line to the intersection, complete the launch of the Andy, the following is a diagram to explain:
Here are a few key points:
1. How to request the intersection:
We use the two-point equation of the straight line:
Can get:
y = (x-x1) * (y2-y2)/(x2-x1) + y1;
Now we know that the X coordinate of the intersection is fixed (either the left or right edge of the screen), so we can easily find the y-coordinate of the intersection according to the formula.
2. How to animate along a path
After finding the coordinates of the intersection, we get a P-point to the intersection of the path (the point above the graph)
Here need to understand Pathmeasure class, do not know can search the Internet, according to the Pathmeasure class, we can get the total length of the path, but also to get the point coordinates on a certain length,
Therefore, the use of property animation, it is worth the change is 0-path.length, when the animation updated according to the length of the time, get the coordinates of the point, and then according to the coordinates of the map of the Andy icon can be ~
Here is all the code for this implementation: When using this view, remember SetBitmap. Of course, using Surfaceview to achieve better, but because I mainly to understand the realization of the idea, it is simple to write.
Package Com.example.myapp.view;import Android.animation.animator;import Android.animation.animatorset;import Android.animation.valueanimator;import Android.content.context;import Android.graphics.bitmap;import Android.graphics.bitmapshader;import Android.graphics.canvas;import Android.graphics.color;import Android.graphics.paint;import Android.graphics.path;import Android.graphics.pathmeasure;import Android.graphics.point;import Android.graphics.rect;import Android.graphics.rectf;import Android.graphics.Shader; Import Android.util.attributeset;import Android.util.displaymetrics;import Android.util.log;import Android.view.motionevent;import Android.view.view;import Android.view.windowmanager;import Android.view.animation.anticipateinterpolator;import Android.view.animation.bounceinterpolator;import Android.view.animation.decelerateinterpolator;import android.view.animation.overshootinterpolator;/** * Created by Yanru.zhang on 16/7/14. * Email:[email protected] */public class MysaibeIERVIEW3 extends View {//two-time bell curve equation//x = (1-t) * (1-t) * p0x + 2 * t * (1-t) * p1x + t * t * P2X; y = (1-t) * (1-t) * p0y + 2 * t * (1-t) * p1y + t * t * P2Y; Private Context Mcontext; Private Paint Mypaint; Private point P0; Two times the beginning of the Bell curve private point P1; Two the control points of the bell curve private point P2; Two times the end of the Bell Curve private point P; A dot on the curve private point bitmapp; The location of the picture points private point centerp; private path Path; Private Path Shootpath; private int downx,downy,movex,movey,upx,upy; Private Bitmap Normalanzai, Moveanzai; Private Bitmap Paintbitmap; private int width,height; Private Boolean Isshootanzai = False, Isresetline = false; Private Bitmapshader Bitmapshader; Private float t = 0.5f; Two times the parameters of the bell Curve T public MySaiBeiErView3 (context context) {this (context,null); } public MySaiBeiErView3 (context context, AttributeSet Attrs) {This (context, attrs, 0); } public MySaiBeiErView3 (context context, AttribuTeset attrs, int defstyleattr) {Super (context, attrs, defstyleattr); Mcontext = context; Displaymetrics displaymetrics = new Displaymetrics (); WindowManager wm = (WindowManager) mcontext.getsystemservice (Context.window_service); Wm.getdefaultdisplay (). Getmetrics (Displaymetrics); width = displaymetrics.widthpixels; Height = displaymetrics.heightpixels; Mypaint = new Paint (); Mypaint.setantialias (TRUE); Mypaint.setstrokewidth (10); Mypaint.setcolor (Color.White); Path = new Path (); Shootpath = new Path (); P0 = new Point (300,height-600); P1 = new Point (); P2 = new Point (width-300,height-600); p = new Point (width/2,height-500); Bitmapp = new Point (); Centerp = new Point (width/2,height-600); } @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (widthmeas Urespec, Heightmeasurespec); MeAsurespec There are 3 modes are unspecified, exactly and at_most,//Then these modes and the layout parameters we normally set fill_parent, wrap_content What is the relationship? The code tests know that when we set width or height to fill_parent, the measure method in which the container calls the child view during layout is exactly, because the child view occupies the space of the remaining container, so its size is deterministic. When set to Wrap_content, the container passes in the At_most, indicating the maximum size of the child view, so that the child view will set its own size according to this limit. When the size of the child view is set to an exact value, the container passes in exactly, and Measurespec's unspecified mode is not currently found under what circumstances. Setmeasureddimension (Width,height); } @Override protected void OnDraw (canvas canvas) {super.ondraw (canvas); LOG.D ("Zyr", "OnDraw");//Android provides Bezier curves in Api=1, just hidden in the Path#quadto () and Path#cubicto () methods, one is the quadratic Bezier curve, One is the Sanche Besel curve. Painting Background mypaint.setstyle (Paint.Style.FILL); Mypaint.setshader (NULL); Canvas.drawrect (0,0,width,height,mypaint); Draw curve if (paintbitmap! = null) {Bitmapshader = new Bitmapshader (Paintbitmap, Shader.TileMode.REPEAT, Shad Er. Tilemode.repeat); Mypaint.setshader (Bitmapshader); } Mypaint.setstyle (Paint.Style.STROKE); Calculate the control point p1.x = (int) ((p.x-(1-T) * (1-t) * p0.x-t * t * p2.x)/(2 * t * (1-T)) according to the two-time bell curve equation; P1.Y = (int) ((P.y-(1-T) * (1-t) * p0.y-t * t * p2.y)/(2 * t * (1-T))); According to the starting point, control point, end point, draw two times path.reset curve (); Path.moveto (P0.X,P0.Y); Path.quadto (P1.X,P1.Y,P2.X,P2.Y); Canvas.drawpath (Path,mypaint); Canvas.drawpoint (P1.x,p1.y,mypaint); if (!isshootanzai &&!isresetline) {//Andy position and position of p are consistent bitmapp.x = P.x-normalanzai.getwidth ()/2 ; BITMAPP.Y = P.y-normalanzai.getheight ()/2; }//Draw icon if (normalanzai!=null && moveanzai!=null) {if (Isshootanzai) {Canv As.drawbitmap (Moveanzai, bitmapp.x, BITMAPP.Y, Mypain T); }else{Canvas.drawbitmap (Normalanzai, bitmapp.x, BITMAPP.Y, Mypaint); }}} @Override public boolean ontouchevent (Motionevent event) {switch (event.getaction ()) { Case MOTIONEVENT.ACTION_DOWN:LOG.D ("Zyr", "Action_down"); DOWNX = (int) event.getrawx (); DownY = (int) Event.getrawy (); if (Isshootanzai | | isresetline) {return false; } p.x = Downx; P.Y = DownY; Invalidate (); return true; Case MOTIONEVENT.ACTION_MOVE:LOG.D ("Zyr", "Action_move"); MoveX = (int) event.getrawx (); Movey = (int) Event.getrawy (); p.x = MoveX; P.Y = Movey; Invalidate (); Break Case MotionEvent.ACTION_CANCEL:case MOTIONEVENT.ACTION_UP:LOG.D ("Zyr", "Action_cancel action_up "); UpX = (int) event.getrawx (); Upy = (int) Event.getrawy (); Bitmapmove (); Break } return Super.ontouchevent (event); public void Setpaintbitmap (Bitmap Bitmap) {if (Bitmap = = null) return; This.paintbitmap = bitmap; Invalidate (); } public void SetBitmap (Bitmap bitmap,bitmap bitmap2) {if (Bitmap = = NULL | | bitmap2 = NULL) return; This.normalanzai = bitmap; This.moveanzai = BITMAP2; Invalidate (); } private void Bitmapmove () {if (Moveanzai = = null) return; Get P1 on top of p0 or below if (p.x <= centerp.x) {shootpath.reset (); Shootpath.moveto (BITMAPP.X,BITMAPP.Y); Shootpath.lineto (width + 100-p.x) * (CENTERP.Y-P.Y)/(centerp.x-p.x) + p.y); }else{//Fly down Shootpath.reset (); Shootpath.moveto (BITMAPP.X,BITMAPP.Y); Shootpath.lineto ( -100, ( -100-p.x) * (CENTERP.Y-P.Y)/(centerp.x-p.x) + p.y); } bitmapanim (); } private void Bitmapanim () {final pathmeasure pathmeasure = new Pathmeasure (shootpath,false); Valueanimator valueanimator = Valueanimator.offloat (0,pathmeasure.getlength ()); Valueanimator.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void O Nanimationupdate (Valueanimator animation) {Float value = (float) animation.getanimatedvalue (); float[] Temppoint = new float[2]; Pathmeasure.getpostan (Value,temppoint,null); BITMAPP.Y = (int) temppoint[1]; bitmapp.x = (int) temppoint[0]; Invalidate (); } }); Valueanimator.addlistener (New Animator.animatorlistener () {@Override public void Onanimationstart (A Nimator animation) {Isshootanzai = true; Resetlineanim (); } @Override public void Onanimationend (Animator animation) {Isshootanzai = false; } @Override public void Onanimationcancel (Animator animation) {Isshootanzai = false; } @Override public void Onanimationrepeat (Animator animation) {}}); Valueanimator.setduration (1000); Valueanimator.setinterpolator (New Overshootinterpolator ()); Valueanimator.start (); } public void Resetlineanim () {Valueanimator Valueanimatorx = Valueanimator.ofint (P.X,WIDTH/2); Valueanimatorx.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void Onanimationupdate (Valueanimator animation) {p.x = (int) animation.getanimatedvalue (); Invalidate (); } }); Valueanimatorx.setduration (200); Valueanimatorx.setinterpolator (New Bounceinterpolator ()); ValueanimAtor valueanimatory = Valueanimator.ofint (p.y,height-500); Valueanimatory.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void Onanimationupdate (Valueanimator animation) {p.y = (int) animation.getanimatedvalue (); Invalidate (); } }); Valueanimatory.setduration (200); Valueanimatory.setinterpolator (New Bounceinterpolator ()); Animatorset animatorset = new Animatorset (); Animatorset.addlistener (New Animator.animatorlistener () {@Override public void Onanimationstart (Ani Mator animation) {Isresetline = true; } @Override public void Onanimationend (Animator animation) {isresetline = false; } @Override public void Onanimationcancel (Animator animation) {Isresetline = false; } @Override Publicvoid Onanimationrepeat (Animator animation) {}}); Animatorset.playtogether (valueanimatorx,valueanimatory); Animatorset.start (); }}
Use the bell curve to achieve imitation 360 drag Andy Clean animation