美文网首页
Android开发艺术探索(6) --- 动画

Android开发艺术探索(6) --- 动画

作者: 官子寒 | 来源:发表于2020-01-25 18:02 被阅读0次

1. View动画

1.1 View动画的种类

  • TranslateAnimation<transalate> 平移动画
  • ScaleAnimation<ScaleAnimation> 缩放动画
  • RotateAnimation<RotateAnimation> 旋转动画
  • AlphaAnimation<AlphaAnimation> 透明度动画
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final Button btn = findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Animation animation = AnimationUtils.loadAnimation(getBaseContext(), R.anim.animation_test);
                btn.startAnimation(animation);
            }
        });

    }
}
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:toXDelta="100"
    android:toYDelta="100"
    android:interpolator="@android:anim/linear_interpolator"
    android:duration="100"/>
    <rotate
        android:duration="100"
        android:fromDegrees="0"
        android:toDegrees="90"/>
</set>

1.2 自定义动画

  • 继承Animation抽象类,重写initializeapplyTransformation方法
  • 主要涉及矩阵变化过程
public class Rotate3dAnimation extends Animation {
    private final float mFromDegree;
    private final float mToDegree;
    private final float mCenterX;
    private final float mCenterY;
    private final float mDepthZ;
    private final boolean mReverse;
    private Camera mCamera;

    public Rotate3dAnimation(float fromDegree, float toDegree, float centerX, float centerY, float DepthZ, boolean reverse) {
        mFromDegree = fromDegree;
        mToDegree = toDegree;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = DepthZ;
        mReverse = reverse;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        final float fromDegree = mFromDegree;
        float degree = fromDegree + (mFromDegree - fromDegree) * interpolatedTime;

        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;

        final Matrix matrix = t.getMatrix();

        camera.save();
        if(mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }
        camera.rotateY(degree);
        camera.getMatrix(matrix);
        camera.restore();

        matrix.preTranslate(-centerX, -centerY);
        matrix.preTranslate(centerX, centerY);
    }
}

1.3 帧动画

帧动画是按顺序播放一组预先设定好的图片

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/colorPrimaryDark" android:duration="500"/>
    <item android:drawable="@color/colorPrimary" android:duration="500" />
    <item android:drawable="@color/colorAccent" android:duration="500" />
</animation-list>
button.setBackgroundResource(R.drawable.animation_drawable);
AnimationDrawable animationDrawable =(AnimationDrawable)button.getBackground();
animationDrawable.start();
帧动画

2. View动画的特殊使用场景

2.1 LayoutAnimation

  • 作用于ViewGroup,子元素出场时都会具有这种动画效果
  • 一般用于ListView这类有子布局的控件

步骤一:定义LayoutAnimation

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:delay="0.5"
    android:animationOrder="normal"
    android:animation="@anim/layout_animation"/>

步骤二:为元素设置具体的出场动画
步骤三:为ViewGroup指定layoutAnimation属性

不仅可以通过XML文件,还可以使用LayoutAnimationController进行实现动画

2.2 Activity的切换效果

  • Activity的默认切换效果是可以变的,主要用到overridePendingTransition(int enterAnim, int exitAnim)
  • overridePendingTransition需要放在startActivity或者finish之后才能生效

3. 属性动画

  • 可以不借助对象来实现动画

3.1 使用属性动画

  • 必须在API 11以上使用,低版本可使用NineOldAndroids兼容
  • 属性动画需要定义在res/animator/
button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ObjectAnimator.ofFloat(button,"translationY", -button.getHeight()).start();
            }
        });
属性动画
  • 属性动画除了用代码定义还可以用XML来定义
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:valueTo="200"
    android:valueType="floatType|intType"
    android:propertyName="y"
    android:repeatCount="1"  
    android:repeatMode="reverse"/>
  • repeatCount:-1表示无限循环,默认为0
  • repeatModerepeat|reverse

3.2 理解插值器和估值器

  • 插值器:根据时间流逝的白分比来计算当前属性值改变的百分比,系统预置的有LinearInterpolator,AccelarateDeccelerateInterpolator,DeccelarateInterpolator
  • 估值器:根据属性改变的百分比来计算改变后的属性值,系统预置的有IntEvaluator,FloatEvaluator,ArgbEvaluator

3.3 属性动画的监听器

  • 属性动画提供了用于监听动画的播放过程的方法,主要有AnimatorUpdateListenerAnimatorListener
valueAnimator = ValueAnimator.ofFloat(0f, 1f);
valueAnimator.setDuration(1000);
valueAnimator.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {
    }
    @Override
    public void onAnimationEnd(Animator animation) {
        System.out.println("valueAnimator.isRunning() " + valueAnimator.isRunning());
    }
    @Override
    public void onAnimationCancel(Animator animation) {
    }
    @Override
    public void onAnimationRepeat(Animator animation) {
    }
});
valueAnimator.start();
  • 系统提供了AnimatorListenerAdapter,可以有选择地监听动画
    ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);  
    fadeAnim.setDuration(250);  
    fadeAnim.addListener(new AnimatorListenerAdapter() {  
    public void onAnimationEnd(Animator animation) {  
        balls.remove(((ObjectAnimator)animation).getTarget());  
    }  
  • 系统提供了AnimatorUpdateListener,每帧都会回调onAnimationUpdate
animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {  
        // You can use the animated value in a property that uses the  
        // same type as the animation. In this case, you can use the  
        // float value in the translationX property.  
        float animatedValue = (float)updatedAnimation.getAnimatedValue();  
        textView.setTranslationX(animatedValue);  
    }  
});

3.4 对任意属性做动画

如果想让属性动画生效,必须满足两个条件:
1)object必须提供setAbc方法,如果动画的时候没有传递初始值,则还要提供getAbc方法,否则会crash
2)objectsetAbc对属性abc的改变必须能够通过某种方法反映出来,比如会改变UI,否则会无效

如果属性动画想改变的属性不存在,想自定义改变的属性时,有3种方法

1. 给你的对象加上get和set方法,如果有权限的话
系统自带的控件都写在Android SDK中,因此只能对自定义View起作用
2. 用一个类来包装原始对象,间接为其提供get和set方法
步骤一:新建wrapper类,传入object对象
步骤二:在wrapper类中实现getAbcsetAbc方法
步骤三:对wrapper对象使用abc属性

注意:setAbc中要调用requestLayout方法
3. 采用ValuAnimator,监听动画过程,自己实现属性的改变

  • valueAnimator不作用于任何object,可以对一个值做动画,在监听过程中改变UI
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final Button button = findViewById(R.id.btn);
//        final Rotate3dAnimation rotate3dAnimation = new Rotate3dAnimation(0, 90, 0, 0,100, false);
//        button.setBackgroundResource(R.drawable.animation_drawable);
//        AnimationDrawable animationDrawable = (AnimationDrawable)button.getBackground();
//        animationDrawable.start();
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                performAnimate(button, button.getWidth(), 500);
            }
        });


    }

    private void performAnimate(final Button button, final int width, final int i) {
        ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 500);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            private IntEvaluator intEvaluator = new IntEvaluator();
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int currentValue = (int)valueAnimator.getAnimatedValue();
                float fraction = (float)valueAnimator.getAnimatedFraction();
                button.getLayoutParams().width = intEvaluator.evaluate(fraction, width, i);
                button.requestLayout();
            }
        });
        valueAnimator.setDuration(500).start();
    }
}
自定义属性动画

相关文章

网友评论

      本文标题:Android开发艺术探索(6) --- 动画

      本文链接:https://www.haomeiwen.com/subject/aupiactx.html