Let's use the following example to show how to use this Animation custom Animation.
In the figure, we can see that the small ball is rolling downward with the track, and the splicing between the track and the track is realized by the second-order Bezier curve. The small ball simulates the gravity effect and the acceleration rolling downward. So, the question here is, what if we simulate this scenario to achieve it?
First of all, we think of Animation with android.
We have studied Animation deeply, and found that there is an ObjectAnimator class. When it is created, there is a related parameter TypeEvaluator and Object. As long as these two classes are implemented, we can achieve the desired trace effect.
No verbosity, post the code
public class PathEvaluator implements TypeEvaluator<PathPoint> { /** * @param t :% executed * @param startValue : Starting point * @param endValue : End * @return */ @Override public PathPoint evaluate(float t, PathPoint startValue, PathPoint endValue) { float x, y; float oneMiunsT = 1 - t; //Third order Bezier curve if (endValue.mOperation == PathPoint.THIRD_CURVE) { x = startValue.mX*oneMiunsT*oneMiunsT*oneMiunsT+3*endValue.mContorl0X*t*oneMiunsT*oneMiunsT+3*endValue.mContorl1X*t*t*oneMiunsT+endValue.mX*t*t*t; y = startValue.mY*oneMiunsT*oneMiunsT*oneMiunsT+3*endValue.mContorl0Y*t*oneMiunsT*oneMiunsT+3*endValue.mContorl1Y*t*t*oneMiunsT+endValue.mY*t*t*t; //Bessel curve of second order }else if(endValue.mOperation == PathPoint.SECOND_CURVE){ x = oneMiunsT*oneMiunsT*startValue.mX+2*t*oneMiunsT*endValue.mContorl0X+t*t*endValue.mX; y = oneMiunsT*oneMiunsT*startValue.mY+2*t*oneMiunsT*endValue.mContorl0Y+t*t*endValue.mY; //straight line }else if (endValue.mOperation == PathPoint.LINE) { //x start point + t * distance between start point and end point x = startValue.mX + t * (endValue.mX - startValue.mX); y = startValue.mY + t * (endValue.mY - startValue.mY); } else { x = endValue.mX; y = endValue.mY; } return PathPoint.moveTo(x,y); } }
public class AnimatorPath { //A series of track recording actions private List<PathPoint> mPoints = new ArrayList<>(); /** * Move to: * @param x * @param y */ public void moveTo(float x,float y){ mPoints.add(PathPoint.moveTo(x,y)); } /** * Move in a straight line * @param x * @param y */ public void lineTo(float x,float y){ mPoints.add(PathPoint.lineTo(x,y)); } /** * Second order Bezier curve movement * @param c0X * @param c0Y * @param x * @param y */ public void secondBesselCurveTo(float c0X, float c0Y,float x,float y){ mPoints.add(PathPoint.secondBesselCurveTo(c0X,c0Y,x,y)); } /** * Third order Bezier curve movement * @param c0X * @param c0Y * @param c1X * @param c1Y * @param x * @param y */ public void thirdBesselCurveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y){ mPoints.add(PathPoint.thirdBesselCurveTo(c0X,c0Y,c1X,c1Y,x,y)); } /** * * @return Return to mobile action set */ public Collection<PathPoint> getPoints(){ return mPoints; } }
public AnimatorPath getRandomPath() { ArrayList<Boolean> array = new ArrayList<>(); animatorPath = new AnimatorPath(); Point point = new Point(); point.set(startPoint.x, startPoint.y); animatorPath.moveTo(point.x, point.y); for (int i = 1; i <= maxTurn; i++) { if (i % 2 == 1) { boolean isLeft = isLeft(); array.add(isLeft); point = isLeft ? makeLeftPath(point) : makeRightPath(point); } else if (i % 2 == 0) { boolean isLeft = isLeft(); array.add(isLeft); if (i != maxTurn) { point = isLeft ? makeLeftPath(point) : makeRightPath(point); if (array.size() > 1 && array.get(array.size() - 2) == isLeft) { point = isLeft ? makeRightPath(point) : makeLeftPath(point); i += 1; } } else { point = isLeft ? makeLeftEndPath(point) : makeRightEndPath(point); } } } return animatorPath; }
private void startAnimatorPath(View view, String propertyName, AnimatorPath path) { if (anim != null && anim.isStarted()) { isStart = false; anim.cancel(); } isStart = true; anim = ObjectAnimator.ofObject(this, propertyName, new PathEvaluator(), path.getPoints().toArray()); anim.setInterpolator(new AccelerateInterpolator(0.85f)); anim.setDuration(8000); anim.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { if (vibrator != null && isStart) { vibrator.vibrate(pattern, -1); //Repeat the above pattern twice. If you want to vibrate only once, the index is set to - 1 } if (mInterstitialAd.isLoaded()) { mInterstitialAd.show(); } else { Log.e("xx", "none"); } } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); anim.start(); }