第七章 Android動畫機制與技巧

Android屬性動畫

    private void objectAnimatorText1() {
        setContentView(R.layout.activity_main);
        final Button button = (Button) findViewById(R.id.bt);
        LinearLayout linearLayout = findViewById(R.id.ll);
        final TextView textViewFirst = linearLayout.findViewById(R.id.tv_first);
        button.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
            @Override
            public void onClick(View v) {
                /**
                 * 操作的屬性必須要有set、get方法,不然無法起效
                 */
                ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(button, "translationX", 300);
                objectAnimator1.start();
                /**
                 * 通過插值器,可以定義動畫變化速率,類似於物理中的加速度
                 *
                 *      線性插值器:在持續時間內,單位時間所移動的距離都是一樣的
                 *      加速度插值器:單位時間內所移動的距離越來越快
                 */
                objectAnimator1.setInterpolator();
                objectAnimator1.addListener(new AnimatorListenerAdapter() {
                    /**
                     * 大部分我們只關心動畫結束事件
                     */
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                    }
                });

                /**
                 * 操作的屬性沒有set、get方法,通過自定義一個屬性類或者包裝類,來間接給這個屬性增加set、get方法
                 */
                WrapperView wrapperView = new WrapperView(button);
                ObjectAnimator objectAnimator2 = ObjectAnimator.ofInt(wrapperView, "width", 300);
                objectAnimator2.start();

                /**
                 * 類似視圖動畫中的AnimationSet
                 */
                PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("translationX", 300f);
                PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
                PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
                ObjectAnimator.ofPropertyValuesHolder(button, holder1, holder2, holder3).setDuration(1000).start();

                /**
                 * ValueAnimator本身不提供任何動畫效果,更像是一個數值發生器,
                 */
                ValueAnimator animator = ValueAnimator.ofInt(0, 400);
                animator.setTarget(button);
                animator.setDuration(1000).start();
                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        /**
                         * 可以使用該數值做想做的事
                         */
                        int animatedValue = (int) animation.getAnimatedValue();
                        Log.i(TAG, "onAnimationUpdate: "+animatedValue);
                        /**
                         * 計時器動畫
                         */
                        textViewFirst.setText(String.valueOf(animatedValue));
                    }
                });
                /**
                 * Android3.0之後,Geogle給View增加了這樣一種簡易的方式驅動屬性動畫
                 */
                button.animate().alpha(0).y(300).setDuration(3000)
                        .withStartAction(new Runnable() {
                            @Override
                            public void run() {

                            }
                        }).withEndAction(new Runnable() {
                    @Override
                    public void run() {

                    }
                }).start();

                /**
                 * 自定義動畫
                 */
                MyAnimation myAnimation = new MyAnimation();
                myAnimation.setDuration(1000);
                button.startAnimation(myAnimation);

            }
        });

        /**
         * 佈局動畫
         */
        LinearLayout linearLayout = findViewById(R.id.ll);
        ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1);
        scaleAnimation.setDuration(2000);
        /**
         * 第一個參數是需要作用的動畫,第二個參數是每個子view顯示的delay時間
         * 當viewGroup添加view的時候,通過LayoutAnimationController定義一個子view的過渡效果
         */
        LayoutAnimationController controller = new LayoutAnimationController(scaleAnimation, 0.5f);
        /**
         * delay時間不爲0的時候可以設置這個
         *
         * 子view出現的順序:
         *      ORDER_NORMAL: 順序
         *      ORDER_RANDOM: 隨機
         *      ORDER_REVERSE: 反序
         */
        controller.setOrder(LayoutAnimationController.ORDER_REVERSE);
        linearLayout.setLayoutAnimation(controller);

    }

    private static class WrapperView{
        private View mTarget;
        public WrapperView(View target){
            mTarget = target;
        }
        public void setWidth(int width){
            mTarget.getLayoutParams().width = width;
            mTarget.requestLayout();
        }
        public int getWidth(){
            return mTarget.getLayoutParams().width;
        }
    }

自定義動畫

/**
 * 自定義動畫
 */
public class MyAnimation extends Animation {

    private Camera mCamera;
    private int mCenterWidth;
    private int mCenterHeight;
    private int mRotateY = 45;
    public MyAnimation(){
        mCamera = new Camera();
    }
    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        setDuration(2000);
        /**
         * 動畫結束後保留狀態
         */
        setFillAfter(true);
        setInterpolator(new BounceInterpolator());
        mCenterWidth = width/2;
        mCenterHeight = height/2;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        /**
         * 獲得當前的矩陣對象
         */
        Matrix matrix = t.getMatrix();
        mCamera.save();
        mCamera.rotateY(mRotateY*interpolatedTime);
        /**
         * 將旋轉變換作用到Matrix
         */
        mCamera.getMatrix(matrix);
        mCamera.restore();
        /**
         * 通過pre方法設置矩陣作用前的偏移量來改變旋轉中心
         */
        matrix.preTranslate(mCenterWidth, mCenterHeight);
        matrix.postTranslate(-mCenterWidth, mCenterHeight);
    }
}

下拉展開動畫

實現類似商城購物車裏的刪除、收藏按鈕。

    private void dropAnimatorText() {
        setContentView(R.layout.drop);
        LinearLayout ll_click = findViewById(R.id.ll_click);
        final LinearLayout hidden_view = findViewById(R.id.hidden_view);
        // 獲取像素密度
        mDensity = getResources().getDisplayMetrics().density;
        /**
         * 獲取佈局的高度,40dp是佈局的高度,這裏轉化爲了像素值
         *
         *   因爲view還沒有測量完畢,所以獲取不到高
         */
        Log.i(TAG, "dropAnimatorText: "+hidden_view.getMeasuredHeight());
        mViewHeight = (int) (mDensity * 40 + 0.5);
        ll_click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (hidden_view.getVisibility() == View.GONE){
                    animataOpen(hidden_view);
                }else {
                    animataClose(hidden_view);
                }
            }
        });
    }

    private void animataClose(final LinearLayout hidden_view) {
        int height = hidden_view.getHeight();
        ValueAnimator animator = createDropAnimator(hidden_view, height, 0);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                hidden_view.setVisibility(View.GONE);
            }
        });
        animator.start();
    }

    private void animataOpen(View hidden_view) {
        hidden_view.setVisibility(View.VISIBLE);
        ValueAnimator animator = createDropAnimator(hidden_view, 0, mViewHeight);
        animator.start();
    }

    private ValueAnimator createDropAnimator(final View hidden_view, int start, int end) {
        ValueAnimator animator = ValueAnimator.ofInt(start, end);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                ViewGroup.LayoutParams layoutParams = hidden_view.getLayoutParams();
                layoutParams.height = animatedValue;
                hidden_view.setLayoutParams(layoutParams);
            }
        });
        return animator;
    }

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章