动画--《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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章