Android应用开发那些事具体自定义控件

自定义 view—贝塞尔曲线的简易玩法

2019-09-30  本文已影响0人  Peakmain
效果图.gif

公式

关于贝塞尔曲线的定义大家可以看贝塞尔曲线的百度百科

代码的实现

public class PathPoint {

    //指令类型
    public static final int MOVE = 0;
    public static final int LINE = 1;
    public static final int CUBIC = 2;
    int mOperation;
    //坐标
    float mX, mY;
    float mControl0x, mControl0y, mControl1x, mControl1y;

    public PathPoint(int operation, float x, float y) {
        mOperation = operation;
        this.mX = x;
        this.mY = y;
    }

    public PathPoint(int operation, int c0x, int c0y, int c1x, int c1y, int x, int y) {
        mOperation = operation;
        this.mX = x;
        this.mY = y;
        this.mControl0x = c0x;
        this.mControl0y = c0y;
        this.mControl1x = c1x;
        this.mControl1y = c1y;
    }
}
public class CustomPath {
    private List<PathPoint> mPathPoints;
    private View mView;
    private int mDuration;
    private TimeInterpolator mInterpolator;

    private CustomPath() {

    }

    public CustomPath(List<PathPoint> pathPoints,int duration, TimeInterpolator interpolator) {
        this.mPathPoints = pathPoints;
        this.mDuration = duration;
        this.mInterpolator = interpolator;
    }

    public void moveTo(float x, float y) {
        mPathPoints.add(new PathPoint(PathPoint.MOVE, x, y));
    }

    public void cubicTo(int c0x, int c0y, int c1x, int c1y, int x, int y) {
        mPathPoints.add(new PathPoint(PathPoint.CUBIC, c0x, c0y, c1x, c1y, x, y));
    }

    public void lineTo(float x, float y) {
        mPathPoints.add(new PathPoint(PathPoint.LINE, x, y));
    }

    public void setDuration(int duration) {
        this.mDuration = duration;
    }

    public void setTimeInterpolator(TimeInterpolator interpolator) {
        this.mInterpolator = interpolator;
    }
    public void startAnimation(View v) {
        this.mView = v;
        ObjectAnimator animator = ObjectAnimator.ofObject(this, "customAnimation", new PathEvalutor(), mPathPoints.toArray());
        animator.setDuration(mDuration);
        animator.setInterpolator(mInterpolator);
        animator.start();
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (beizeAnimationEnd != null) {
                    beizeAnimationEnd.animationEnd(animation);
                }
            }
        });
    }

    public void setCustomAnimation(PathPoint pathPoint) {
        mView.setTranslationX(pathPoint.mX);
        mView.setTranslationY(pathPoint.mY);
    }
    public static class Builder {
        private List<PathPoint> mPathPoints;
        private int mDuration;
        private TimeInterpolator mInterpolator;

        public Builder() {
            mPathPoints = new ArrayList<>();
            mDuration = 250;
            mInterpolator = new LinearInterpolator();
        }

        public Builder moveTo(float x, float y) {
            mPathPoints.add(new PathPoint(PathPoint.MOVE, x, y));
            return this;
        }

        public Builder cubicTo(int c0x, int c0y, int c1x, int c1y, int x, int y) {
            mPathPoints.add(new PathPoint(PathPoint.CUBIC, c0x, c0y, c1x, c1y, x, y));
            return this;
        }

        public Builder lineTo(float x, float y) {
            mPathPoints.add(new PathPoint(PathPoint.LINE, x, y));
            return this;
        }

        public Builder setDuration(int duration) {
            this.mDuration = duration;
            return this;
        }

        public Builder setTimeInterpolator(TimeInterpolator interpolator) {
            this.mInterpolator = interpolator;
            return this;
        }

        public CustomPath build() {
            return new CustomPath(mPathPoints, mDuration, mInterpolator);
        }
    }


    //动画结束
    public interface BeizeAnimationEnd {
        public void animationEnd(Animator animation);
    }

    private BeizeAnimationEnd beizeAnimationEnd;

    public void addBeizeAnimationEnd(BeizeAnimationEnd beizeAnimationEnd) {
        this.beizeAnimationEnd = beizeAnimationEnd;
    }

}

主要思路:1、我们可能会有多个指令类型一起执行,所以我们可以将所有的指令类型封装到一个集合中
2、执行动画使用属性动画ObjectAnimator.ofObject来执行
3、

 ObjectAnimator animator = ObjectAnimator.ofObject(this, "customAnimation", new PathEvalutor(), mPathPoints.toArray());

customAnimation可以是任何名字,heihei也可以对应的是setHeihei。

public class PathEvalutor implements TypeEvaluator<PathPoint> {
    @Override
    public PathPoint evaluate(float t, PathPoint startValue, PathPoint endValue) {
        float x, y;
        if (endValue.mOperation == PathPoint.CUBIC) {//贝塞尔曲线
            float oneMinusT = 1 - t;
            x = oneMinusT * oneMinusT * oneMinusT * startValue.mX +
                    3 * oneMinusT * oneMinusT * t * endValue.mControl0x +
                    3 * oneMinusT * t * t * endValue.mControl1x +
                    t * t * t * endValue.mX;
            y = oneMinusT * oneMinusT * oneMinusT * startValue.mY +
                    3 * oneMinusT * oneMinusT * t * endValue.mControl0y +
                    3 * oneMinusT * t * t * endValue.mControl1y +
                    t * t * t * endValue.mY;
        } else if (endValue.mOperation == PathPoint.LINE) {
            x = startValue.mX + t * (endValue.mX - startValue.mX);
            y = startValue.mY + t * (endValue.mY - startValue.mY);
        } else {
            x = endValue.mX;
            y = endValue.mY;
        }
        return new PathPoint(PathPoint.MOVE,x,y);
    }
}
   mPath = new CustomPath.Builder()
                        .moveTo(0, 0)
                        .setDuration(1000)
                        .cubicTo(-200, 200, -400, 200, -600, 50)
                        .build();
            /*    mPath.moveTo(0, 0);
                mPath.cubicTo(-200, 200, -400, 200, -600, 50);
                mPath.lineTo(-900,200);
                mPath.lineTo(0,0);
                mPath.setDuration(1000);*/
                mPath.startAnimation(v);
                mPath.addBeizeAnimationEnd(new CustomPath.BeizeAnimationEnd() {
                    @Override
                    public void animationEnd(Animator animation) {
                        mLlTitle.setVisibility(View.INVISIBLE);
                        mFab.setVisibility(View.INVISIBLE);
                        mLinearLayout.setVisibility(View.VISIBLE);
                        mToolBar.setBackgroundColor(getResources().getColor(R.color.brand_accent));
                        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
                        valueAnimator.setDuration(1000);
                        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator animation) {
                              findViewById(R.id.iv_prev).setAlpha((Float) animation.getAnimatedValue());
                              findViewById(R.id.iv_pause).setAlpha((Float) animation.getAnimatedValue());
                              findViewById(R.id.iv_next).setAlpha((Float) animation.getAnimatedValue());
                            }
                        });
                        valueAnimator.start();
                    }
                });

总结:代码其实很简单,主要是公式的套入和在ObjectAnimator的使用情况下需要对源码有一点了解

上一篇 下一篇

猜你喜欢

热点阅读