Animation custom animation track of android

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();
    }

Keywords: Android Mobile

Added by cello on Fri, 01 May 2020 21:40:43 +0300