Android炫酷的播放效果

一、首先看效果

Android炫酷的播放效果_第1张图片

二、实现原理

使用贝塞尔曲线实现滑动效果,在使用属性动画实现水波纹效果,然后就能实现以上效果

三、实现

1、先封装动画框架,创建动画基础类

PathPoint.java

public class PathPoint {

    public static final int MOVE = 0;
    public static final int LINE = 1;
    public static final int CURVE = 2;
    float mControl0X, mControl0Y;
    float mControl1X, mControl1Y;
    public float mX, mY;
    int mOperation;

    //line/move
    private PathPoint(int operation, float x, float y) {
        this.mOperation = operation;
        this.mX = x;
        this.mY = y;
    }

    //curve
    private PathPoint(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {
        this.mControl0X = c0X;
        this.mControl0Y = c0Y;
        this.mControl1X = c1X;
        this.mControl1Y = c1Y;
        this.mX = x;
        this.mY = y;
        this.mOperation = CURVE;

    }

    public static PathPoint moveTo(float x, float y) {

        return new PathPoint(MOVE, x, y);

    }

    public static PathPoint lineTo(float x, float y) {

        return new PathPoint(LINE, x, y);

    }

    public static PathPoint curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {

        return new PathPoint(c0X, c0Y, c1X, c1Y, x, y);

    }
}

创建动画集合类,并且保存绘制轨迹

AnimatorPath
public class AnimatorPath {
    //记录轨迹
    private List mPoints = new ArrayList<>();

    public void moveTo(float x, float y) {
        mPoints.add(PathPoint.moveTo(x, y));
    }

    public void lineTo(float x, float y) {
        mPoints.add(PathPoint.lineTo(x, y));
    }

    public void curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {
        mPoints.add(PathPoint.curveTo(c0X, c0Y, c1X, c1Y, x, y));
    }


    public Collection getPoints() {
        return mPoints;
    }
}

3、实现页面布局





    

    

        

            
            
        
    

    

        

            

            

            

        

        
    

4、获取控件,并且设置点击事件,设置一些动画常量

private View mFab;
    private FrameLayout mFabcontainer;
    private LinearLayout mControlsContainer;

    //从什么时候开始执行动画
    private static final float SCALE_FACTOR = 13f;
    //持续时间
    private static final long ANIMATION_DURATION = 300;
    //贝塞尔曲线滑动到什么时候开始执行动画
    private static final float MINIMUN_X_DISTANCE = 200;
    private boolean mRevealFlag;
    private float mFabSize;

5,给mFab设置点击事件

private void onFabPressed(View view) {
        final float startX = mFab.getX();
        //开始动画
        AnimatorPath path = new AnimatorPath();
        path.moveTo(0, 0);
        path.curveTo(-200, 200, -400, 100, -600, 50);
//        path.lineTo(-600,50);

        ObjectAnimator anim = ObjectAnimator.ofObject(this, "fabLoc",
                new PathEvaluator(), path.getPoints().toArray());
        anim.setInterpolator(new AccelerateInterpolator());
//        anim.setRepeatCount(ValueAnimator.INFINITE);
//        anim.setRepeatMode(ValueAnimator.REVERSE);
        anim.setDuration(ANIMATION_DURATION);
        anim.start();
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                //到了path路径中的某个位置就是开始扩散动画
                if (Math.abs(startX - mFab.getX()) > MINIMUN_X_DISTANCE) {
                    if (!mRevealFlag) {
                        ImageButton fab = (ImageButton) mFab;
                        fab.setImageDrawable(new BitmapDrawable());
                        //看布局里边的FabContainer要比toolbar背景高mFabSize/2(为了最初的半个fab效果)
                        mFabcontainer.setY(mFabcontainer.getY() + mFabSize / 2);
                        //fab放大动画
                        mFab.animate()
                                .scaleXBy(SCALE_FACTOR)
                                .scaleYBy(SCALE_FACTOR)
                                .setListener(mEndRevealListener)
                                .setDuration(ANIMATION_DURATION);
                        mRevealFlag = true;
                    }
                }
            }
        });
    }

    public void setFabLoc(PathPoint newLoc) {
        mFab.setTranslationX(newLoc.mX);
        if (mRevealFlag) {
            //因为布局里边的mFabcontainer要比toolbar背景高mFabSize/2,所以fab为了看起来平顺,需要上移mFabSize/2
            mFab.setTranslationY(newLoc.mY - (mFabSize / 2));
        } else {
            mFab.setTranslationY(newLoc.mY);
        }

    }

    private AnimatorListenerAdapter mEndRevealListener = new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            mFab.setVisibility(View.INVISIBLE);
            mFabcontainer.setBackgroundColor(getResources().getColor(R.color.colorAccent));
            //reveal动画完毕后,接着每一个子控件都有个缩放动画(依次顺序出来)
            for (int i = 0; i < mControlsContainer.getChildCount(); i++) {
                View v = mControlsContainer.getChildAt(i);
                ViewPropertyAnimator animate = v.animate()
                        .scaleX(1)
                        .scaleY(1)
                        .setDuration(ANIMATION_DURATION);
                animate.setStartDelay(i * 50);
                animate.start();
            }
        }
    };
PathEvaluator
public class PathEvaluator implements TypeEvaluator {
    @Override
    public PathPoint evaluate(float t, PathPoint startValue, PathPoint endValue) {
        //t执行的百分比  (0~1)
        float x, y;
        if (endValue.mOperation == PathPoint.CURVE) {
            //三阶贝塞尔曲线 公式
            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.mControl1X +
                    t * t * t * endValue.mY;
        } else if (endValue.mOperation == PathPoint.LINE) {
            //x=起始点+t*起始点和终点的距离
            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);
    }
}

注意:属性动画既可以改变属性,也可以改变一个变量或者方法

你可能感兴趣的:(Android原创)