Android动画深入分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wanggang514260663/article/details/78029622

Android的动画可以分为三种: View动画、帧动画、属性动画。其实帧动画也属于View动画,只不过它和平移、旋转等常见的View动画在表现形式上略有不同而已。View动画通过对场景里的对象的不断做图像变换(平移、缩放、旋转、透明度)从而产生动画效果,它是一种渐进式动画,并且View动画支持自定义。帧动画通过顺序播放一系类图像从而产生动画效果,可以简单理解为图片切换动画,很显然,如果图片过多过大就会导致OOM。属性动画通过动态的改变对象的属性而达到动画效果。

1、View动画

View动画的作用对象是View,它支持四种动画效果,分别是平移、缩放、旋转、透明度动画。

1-1、View动画的种类

View动画的四种变换效果对应着Animation的四个子类: TranslateAnimation、ScaleAnimation、RotateAnimation和AlphaAnimation,这四种动画既可以用xml定义,也支持代码来动态创建。

名称 标签 子类 效果
平移动画 TranslateAnimation 移动View
缩放动画 ScaleAnimation 放大或者缩小View
旋转动画 RotateAnimation 旋转View
透明度动画 AlphaAnimation 改变View的透明度

要使用View动画,首先要创建动画的XML文件,这个文件的路径为:res/anim/xxxx.xml

View的动画即可以是单个动画,也支持一系列的动画组合。

xml文件创建动画样式

<?xml version="1.0" encoding="utf-8">
<set xmlns:android="xxxxxx"
    android:fillAfter="true"
    android:zAdjustment="normal">
    
    <translate
        android:duration="100"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXdelta="100"
        android:toYdelta="100"/>
</set>

如果需要使用上面的动画,如下:

Button btn = findViewById(R.id.btn);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_test);
btn.startAnimation(animation);

除了使用xml创建动画之外,还可以使用代码创建。

AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(300);

View动画提供了动画变化事件监听:

public static interface AnimationListener{
    void onAnimationStart(Animation animation);
    void onAnimationEnd(Animation animation);
    void onAnimationRepeat(Animation animation);
}

1-2、自定义View动画

自定义View动画,只要是继承Animation这个抽象类,然后重写它的initialize和applyTransformation方法,在initialize中进行初始化工作,在applyTransformation中进行相应的矩阵变换。

1-3、帧动画

帧动画是顺序播放一组预先定义好的图片,类似于电影播放。不同于View动画,系统提供了另一个类AnimationDrawable来使用帧动画。

<?xml version="1.0" encoding="utf-8">
<animation-list>
    <item android:drawable="" android:duration="500"/>
    ...
</animation-list>

然后将上述的Drawable作为View的背景并通过Drawable来播放动画即可。

Button button = findViewById(R.id.button);
button.setBackgroundResource(R.drawable.frame_animation);
AnimationDrawable drawable = button.getBackground();
drawable.start();

帧动画使用简单,但是容易出现OOM,使用中要注意单个图片大小。

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

除了四种形式外,View动画还可以在一些特殊场景下使用,比如ViewGroup中可以控制子元素的出场效果,在Activity中可以实现不同Activity的切换。

2-1、LayoutAnimation

LayoutAnimation作用于ViewGroup,为ViewGroup指定一个动画,这样当它的子元素出场的时候就会具有这种动画效果。

给ViewGroup的子元素添加出场动画,遵循如下过程:

  • 1、定义LayoutAnimation
//res/anim/anim_layout.xml
<layoutAnimation
    xmlns:android="xxxxxx"
    android:delay="0.5"             //指定子元素动画开始延迟
    android:animationOrder="normal"  //子元素动画顺序,有三种选项: normal、reverse、random
    android:animation="@anim/xxxxx"   //指定view的具体实现文件
>
</layoutAnimation>
  • 2、为子元素定义具体的入场动画
<?xml version="1.0" encoding="utf-8">
<set xmlns:android="xxxxx">
    //view动画实现
</set>
  • 3、使用ViewGroup子类的android:layoutAnimation设置动画或者使用代码设置
Animation animation = AnimationUtils.loadAnimation();
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
viewgroup.setLayoutAnimation(controller);

2-2、Activity的切换效果

Activity切换动画自定义主要用到overridePendingTransition(int enterAnim, int exitAnim),这个方法必须要在startAnimation或者finish之后调用才能生效。

  • enterAnim: Activity被打开时,所需的动画资源id。
  • exitAnim:Activity被暂停时,所需的动画资源id。

启动一个Activiy

Intent intent = new Intent(xxxx, xxxx);
startActivity(intent);
overridePendingTransition(R.anim.enter_anim, R.anim_exit_anim);

退出Activity

finish();
overridePendingTransition(R.anim.enter_anim, R.anim_exit_anim);

Fragment切换动画,可以使用FragmentTransiton的setCustomAnimation方法添加

3、属性动画

3-1、使用属性动画

属性动画可以使用代码定义,也可以使用xml定义

代码定义

ObjectAnimatior.ofFloat(mObject, "translateY", -mObject.getHeight()).start();

xml定义的话,需要放在res/animator/目录下,定义语法如下

<set android:ordering=["together" | "sequentially"]>
    <objectAnimator 
        android:propertyName="string"  //属性动画的作用对象的属性名称
        android:duration="int"  //动画时长
        android:valueFrom="float|int|color"  //属性的开始值
        android:valueTo="float|int|color" //属性的结束值
        android:startOffset="int"  //动画的延迟时间
        android:repeatCount="int"  //重复次数
        android:repeatMode=["repeat" | "reverse"] //重复方式
        android:valueType=["intType" | "floatType"]/>  //属性的类型
</set>

xml定义的属性动画使用方式如下:

AnimatorSet set = AnimatorInflator.loadAnimator(context, R.anim.propertry_animator);
set.setTarget(button);
set.start();

3-2、理解插值器和估值器

TimeInterpolator是时间插值器,它的作用是根据时间流逝的百分比来计算出当前属性值改变的百分比,系统预置的有LinearInterpolator(线性插值器:匀速动画)、AccelerateDecelerateInterpolator(加速减速插值器:两头慢中间快)和DecelerateInterpolator(减速插值器:动画越来越慢)。

TypeEvaluator是类型估值算法,它的作用是根据当前属性改变的百分比来计算改变后的属性值,系统预置的有IntEvalutor(针对整型属性)、FloatEvalutor(针对浮点型属性)和ArgbEvalutor(针对Color的属性)。

自定义插值器需要实现Interpolator或者TimeInterpolator,自定义估值器算法需要实现TypeEvaluator。

3-3、属性动画的监听器

属性动画提供了监听器用于监听动画的播放过程,主要有如下两个接口: AnimatorUpdateListener和AnimatorListener。

AnimatorListner的定义如下:

public static interface AnimatorListener{
    void onAnimationStart(Animator animator);
    void onAnimationEnd(Animator animator);
    void onAnimationCancel(Animator animator);
    void onAnimationRepeat(Animator animator);
}

AnimatorUpdateListener的定义如下:

public static interface AnimatorUploadListener{
    void onAnimationUpdate(ValueAnimator animator);
}

AnimatorUpdateListener比较特殊,它会监听整个动画过程,动画由许多帧构成,没播放一帧,onAnimationUpdate就会被调用一次。

3-4、对任意属性做动画

我们对object的属性abc做动画,如果想要动画生效,必须满足两个条件:

  • 1、object必须提供setAbc方法,如果动画的时候没有传递初始值,那么还要提供getAbc方法,因为系统要去取abc的初始值(如果这个条件不满足,程序直接Crash)
  • 2、object的setAbc对属性abc所做的改变必须能够通过某种方法反映出来,比如会带来UI的改变之类的(如果这条不满足,动画无效果但不会Crash)

如果我们需要改变的属性没有提供get、set的话,官方文档提供了三种处理方式建议:

  • 1、给你的对象加上set、get方法,如果你要权限的话。(通常情况下,对象都是在sdk里面实现的,所以这个很多情况是行不通的)
  • 2、用一个类包装原始对象,间接为其提供get、set方法(这种方式是比较常用的)
  • 3、采用ValueAnimator,监听动画过程,自己实现属性的改变(这种方案也是比较常用的)

4、使用动画的注意事项

  • 1、OOM问题

这个问题在帧动画比较容易出现,如果图片数量比较多且图片较大的时候,很容易造成OOM。

  • 2、内存泄漏

对于无限循环的动画,需要在activity结束的时候及时停止, 防止导致activity对象无法释放导致的内存泄漏

  • 3、兼容性问题

注意处理view的动画支持的版本情况,根据场景做适配。

  • 4、View动画的问题

View动画是对View的影像做动画,并不是真正的改变view的状态,因此有时候会出现动画完成后view无法影藏的现象,即setVisiblitity(View.Gone)失效,这个时候只要调用view.clearAnimation()清除view动画即可解决这个问题。

  • 5、不要使用px

进行动画过程中,要尽量使用dp,使用px会导致在不同的设备上有不同的效果。

  • 6、动画元素的交互

将view移动后,事件焦点是不会改变的,不管view动画还是属性动画,新位置都是无法触发点击事件的。同时老位置是可以点击的。这种情况下,尽可能在view的视觉变化后,将老的视图移动,并在新位置构建一个动画副本。

  • 7、硬件加速

在动画的过程中,建议开启硬件加速,会增加动画的流畅性

猜你喜欢

转载自blog.csdn.net/wanggang514260663/article/details/78029622