動畫--《Android開發藝術探索》閱讀筆記——第七章 TODO


/**
 * 動畫 測試
 * @author hufeiyang
 */
public class AnimationTestActivity extends AppCompatActivity {

    private Unbinder unbinder;

    @BindView(R.id.textView1)
    TextView textView1;

    @BindView(R.id.textView2)
    TextView textView2;

    @BindView(R.id.textView3)
    TextView textView3;

    @BindView(R.id.textView4)
    TextView textView4;

    @BindView(R.id.button_animator_test)
    Button button;
    private AnimatorSet mAnimatorSet;


    public static void launch(Activity activity) {
        Intent intent = new Intent(activity, AnimationTestActivity.class);
        activity.startActivity(intent);
        //overridePendingTransition必須位於startActivity會finish的後面,纔會有動畫效果
        activity.overridePendingTransition(R.anim.enter_from_right, 0);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation_test);
        unbinder = ButterKnife.bind(this);

        viewAnimationTest();

        objectAnimatorTest();

        testAnimatorAboutButtonWidth();
    }

    /**
     * 屬性動畫test
     * 屬性動畫幾乎無所不能,只要對象有這個屬性,就可以對這個屬性做動畫。
     * 原理:內部通過反射 調用對應屬性的set、get方法。
     *
     *
     * 差值器:Interpolator,根據 時間流逝的百分比,計算,當前屬性值改變的百分比。
     * 例如duration是1000,start後過了200,那麼時間百分比是0.2,那麼如果差值器是LinearInterpolator線性差值器,那麼屬性值改變的百分比也是0.2
     *
     * 估值器:Evaluator,就是根據 差值器獲取的 屬性值百分比,計算改變後的屬性值。
     * ofInt、onFloat內部會自動設置IntEvaluator、FloatEvaluator。如果使用ofInt且是顏色相關的屬性,就要設置ArgbEvaluator。見下面 文字顏色變化 的例子。
     *
     */
    private void objectAnimatorTest() {
        //屬性動畫使用,方式一:代碼,建議使用。
        //setTranslationX,像view動畫一樣,view實際的layout位置沒變,改變了視圖位置,但是 給觸摸點生效區域增加了位移。(而view動畫僅改變了視圖位置)
        ObjectAnimator translationX = ObjectAnimator
                .ofFloat(textView4, "translationX", 0, 200)
                .setDuration(1000);
        translationX.setInterpolator(new LinearInterpolator());
        setAnimatorListener(translationX);

        //屬性動畫使用,方式二:xml。
        Animator animatorUpAndDown = AnimatorInflater.loadAnimator(this, R.animator.animator_test);
        animatorUpAndDown.setTarget(textView4);

        //文字顏色變化
        ObjectAnimator textColor = ObjectAnimator
                .ofInt(textView4, "textColor", 0xffff0000, 0xff00ffff)
                .setDuration(1000);
        textColor.setRepeatCount(ValueAnimator.INFINITE);
        textColor.setRepeatMode(ValueAnimator.REVERSE);
        //注意,這裏如果不設置 那麼顏色就是跳躍的,設置ArgbEvaluator 就是連續過度的顏色變化
        textColor.setEvaluator(new ArgbEvaluator());

        //animatorSet
        mAnimatorSet = new AnimatorSet();
        mAnimatorSet
                .play(animatorUpAndDown)
                .with(textColor)
                .after(translationX);

        mAnimatorSet.start();

    }

    /**
     * 對任意屬性做動畫 要求兩個條件:
     *      1、object有對應屬性的set方法,沒設置初始值還要有get方法。
     *      2、set方法要對object有所改變,如UI的變化。(如TextView調用setWidth方法卻不會改變UI,那就不產生動畫)
     *
     *  當不滿足條件時,有如下處理方法:
     *      1、給object添加set、get方法,如果有權限。(一般不行,如TextView是SDK裏面的不能直接改)
     *      2、給Object包裝一層,在包裝類中提供set、get方法。{@link #}
     *      3、使用ValueAnimator,監聽Value變化過程,自己實現屬性的改變。
     */
    private void testAnimatorAboutButtonWidth() {
        //Button width 屬性動畫:如果xml中寬度是wrap_content,那麼動畫有效。
        // 如果設置button確切的dp值,那麼無效,因爲對應屬性"width"的setWidth()方法就是 在wrap_content是纔有效。
        ObjectAnimator width1 = ObjectAnimator.ofInt(button, "width", 600);
        width1.setDuration(2000);
//        width1.start();

        //那麼,想要在button原本有確切dp值時,要能對width動畫,怎麼做呢?
        //方法一,包一層,然後用layoutParams
        ViewWrapper wrapper = new ViewWrapper(button);
        ObjectAnimator width2 = ObjectAnimator.ofInt(wrapper, "width", 600);
        width2.setDuration(2000);
//        width2.start();

        //方法二,使用ValueAnimator,每一幀自己顯示寬度的變化
        ValueAnimator valueAnimator = ValueAnimator.ofInt(button.getLayoutParams().width, 600);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = (Integer) animation.getAnimatedValue();
                Log.i("hfy", "onAnimationUpdate: animatedValue="+animatedValue);

//                IntEvaluator intEvaluator = new IntEvaluator();
////                獲取屬性值改變比例、計算屬性值
//                float animatedFraction = animation.getAnimatedFraction();
//                Integer evaluate = intEvaluator.evaluate(animatedFraction, 300, 600);
//                Log.i("hfy", "onAnimationUpdate: evaluate="+evaluate);


                button.getLayoutParams().width = animatedValue;
                button.requestLayout();
            }
        });

        valueAnimator.setDuration(4000).start();

    }

    private void setAnimatorListener(ObjectAnimator translationX) {
        translationX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //每播放一幀,都會調用
            }
        });
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            translationX.addPauseListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationResume(Animator animation) {
                    super.onAnimationResume(animation);
                }
            });
        }

        translationX.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }
        });
    }




    /**
     * view動畫test
     */
    private void viewAnimationTest() {
        //view動畫使用,方式一:xml,建議使用。
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_test);
        textView1.startAnimation(animation);

        //view動畫使用,方式二:new 動畫對象
        AnimationSet animationSet = new AnimationSet(false);
        animationSet.setDuration(3000);
        animationSet.addAnimation(new TranslateAnimation(0, 100, 0, 0));
        animationSet.addAnimation(new ScaleAnimation(0.1f, 1f, 0.1f, 1f));
        animationSet.setFillAfter(true);
        textView2.startAnimation(animationSet);

        //view動畫使用,方式二:new 動畫對象,使用setAnimation
        AnimationSet animationSet2 = new AnimationSet(false);
        animationSet2.setDuration(3000);
        animationSet2.addAnimation(new TranslateAnimation(0, 100, 0, 0));
        animationSet2.addAnimation(new ScaleAnimation(0.1f, 1f, 0.1f, 1f));
        animationSet2.setFillAfter(true);
        animationSet2.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                MyToast.showMsg(AnimationTestActivity.this, "View動畫:代碼 set:View動畫結束~");
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        textView3.setAnimation(animationSet2);
    }

    @OnClick({R.id.button_animator_test,
            R.id.textView4})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.button:
//                linearLayout.addView(new Button(this));
            break;
            case R.id.textView4:
                MyToast.showMsg(this, "點了textView4");
                break;
            default:
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbinder.unbind();

        if (mAnimatorSet != null && mAnimatorSet.isRunning()) {
            mAnimatorSet.cancel();
        }
    }

    @Override
    public void finish() {
        super.finish();
        overridePendingTransition(0, R.anim.exit_to_right);
    }


    /**
     * 包一層,提供對應屬性的set、get方法
     */
    private class ViewWrapper {

        private final View mView;

        public ViewWrapper(View view) {
            mView = view;
        }

        public int getWidth(){
            return mView.getLayoutParams().width;
        }

        public void setWidth(int width){
            ViewGroup.LayoutParams layoutParams = mView.getLayoutParams();
            layoutParams.width = width;
            mView.setLayoutParams(layoutParams);
            mView.requestLayout();
        }
    }


}

R.anim.animation_test

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:duration="5000"> <!--set裏面的duration如果有值,會覆蓋子標籤的duration-->

    <translate
        android:fromXDelta="0"
        android:toXDelta="200"
        android:duration="1000"/>
    <scale android:fromXScale="0.5"
        android:toXScale="1"
        android:fromYScale="0.5"
        android:toYScale="1"
        android:duration="2000"/>
    <alpha android:fromAlpha="0.2"
        android:toAlpha="1"
        android:duration="3000"/>
</set>

R.animator.animator_test

<?xml version="1.0" encoding="utf-8"?>
<!--屬性動畫test,一般建議採用代碼實現,不用xml-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially">


    <!--repeatCount:默認是0-1是無限循環-->
    <!--repeatMode:重複模式:restart-從頭來一遍、reverse-反向來一遍-->
    <!--valueType:指定propertyName的類型可選intType、floatType-->

    <!--android:pathData=""
        android:propertyXName=""
        android:propertyYName=""-->
    <objectAnimator
        android:propertyName="translationY"
        android:duration="1000"
        android:valueFrom="0"
        android:valueTo="200"
        android:startOffset="0"
        android:repeatCount="0"
        android:repeatMode="reverse"
        android:valueType="floatType"
        android:interpolator="@android:interpolator/accelerate_decelerate" />

    <!--animator對用vueAnimator,比objectAnimator少了propertyName-->
    <!--<animator-->
        <!--android:duration="2000"-->
        <!--android:valueFrom=""-->
        <!--android:valueTo=""-->
        <!--android:startOffset=""-->
        <!--android:repeatCount=""-->
        <!--android:repeatMode=""-->
        <!--android:valueType=""-->
        <!--android:interpolator=""-->
        <!--android:pathData=""-->
        <!--android:propertyXName=""-->
        <!--android:propertyYName=""/>-->

</set>

R.anim.enter_from_left

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="500"
        android:fromXDelta="-100%p"
        android:toXDelta="0"/>

</set>

R.anim.enter_from_right

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="500"
        android:fromXDelta="-100%p"
        android:toXDelta="0"/>

</set>

R.anim.exit_to_left

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="500"
        android:fromXDelta="-100%p"
        android:toXDelta="0"/>

</set>

R.anim.exit_to_right

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="500"
        android:fromXDelta="-100%p"
        android:toXDelta="0"/>

</set>
發佈了54 篇原創文章 · 獲贊 16 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章