Android(Animation框架)动画原理:
控制的是整个View,原理:每次绘制视图时View所在的ViewGroup中的drawChild()获取该View的Animation的Transformation值,然后调用canvas.concat(transfromToApply.getMatrix()),通过矩阵换算完成动画帧,如果没有完成,就继续调用invalidate(),启动下次绘制来驱动动画,直到完成动画的绘制。
动画分类:
帧动画
补间动画
属性动画
动画常见展现形式:
透明度
旋转
缩放
位移
一、帧动画:
原理:通过顺序播放一系列图像从而产生动画效果(ps:如果图片过大就会导致OOM)
使用:
在drawable文件中新建文件:
<?xml version="1.0" encoding="utf-8"?>
<!-- android:oneshot="false" false动画循环执行 true动画执行一次-->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/img_1" android:duration="500"/>
<item android:drawable="@drawable/img_2" android:duration="500"/>
<item android:drawable="@drawable/img_3" android:duration="500"/>
<item android:drawable="@drawable/img_4" android:duration="500"/>
</animation-list>
代码调用:
imageView = (ImageView) findViewById(R.id.img); imageView.setImageResource(R.drawable.frame_anim);
AnimationDrawable drawable = (AnimationDrawable) imageView.getDrawable();
drawable.start();
二、补间动画:
原理:通过对场景里的对象不断做图像变换从而产生动画效果(View动画的作用对象是View)
种类:
ScaleAnimation
RotateAnimation
Transformation
AlphaAnimation
xml用法:
在res/anim文件中新建文件:
<?xml version="1.0" encoding="utf-8"?><!-- android:shareInterpolator="false" 表示集合中的动画是否共享同一个插值器-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<alpha
android:fromAlpha="float"
android:toAlpha="float" />
<scale
android:fromXScale="float"
android:fromYScale="float"
android:pivotX="float"
android:pivotY="float"
android:toXScale="float"
android:toYScale="float" />
<translate
android:fromXDelta="float"
android:fromYDelta="float"
android:toXDelta="float"
android:toYDelta="float" />
<rotate
android:fromDegrees="float"
android:pivotX="float"
android:pivotY="float"
android:toDegrees="float" />
</set>
代码调用:
imageView = (ImageView) findViewById(R.id.img);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.set_animation);
imageView.startAnimation(animation);
代码使用:自行google
监听事件:
public static interface AnimationListener {
void onAnimationStart(Animation animation);
void onAnimationEnd(Animation animation);
void onAnimationRepeat(Animation animation);
}
三、属性动画:
原理:通过动态改变对象的属性从而达到动画效果(API 11新特性,不能向下兼容,故有nineoldandroids兼容库)
属性动画除了视图动画的四种,还可以实现刚加绚丽的动画,视图动画主要依于Animation抽象类,而属性动画依于Animator抽象类,我们看下Animator的扩展类:
常用的类就是AnimatorSet 、ObjectAnimator、 ValueAnimator
其中 ValueAnimator 是 ObjectAnimator的基类
xml用法:
在drawable文件中新建文件:
<?xml version="1.0" encoding="utf-8"?><!--android:ordering="sequentially|together" 按顺序播放|一起播放-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially">
<animator
android:duration="100"
android:interpolator=""
android:repeatCount=""
android:repeatMode=""
android:startOffset=""
android:valueFrom=""
android:valueTo=""
android:valueType=""/>
<objectAnimator
android:duration=""
android:valueType=""
android:valueTo=""
android:valueFrom=""
android:startOffset=""
android:interpolator=""
android:pathData=""
android:propertyName=""
android:propertyXName=""
android:propertyYName=""
android:repeatCount=""
android:repeatMode=""
/>
</set>
上面的属性值我并没有给出,相信小伙伴大部分都知道,我就不解释了,
代码调用:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.anim.ainmatorset);
set.setTarget(imageView);
set.start();
代码用法: 自行Google
插值器&估值器:
TimeInterpolator:时间差值器,根据时间流逝的百分比,来计算当前属性值改变的百分比。
源码中Interpolator接口继承TimeInterpolator
Interpolator的实现类如下:
常用的插值器有:
LinearInterpolator(线性插值器:匀速动画)
AccelerateDecelerateInterpolator(加速减速插值器:动画两头慢中间快)
DecelerateInterpolator(减速插值器:动画越来越慢)
。。。。。。。等TypeEvaluator:类型估值算法,又叫估值器。根据当前属性改变的百分比来计算改变后的属性值。
常用的估值器:
属性动画中的插值器&估值器是实现非匀速动画的重要手段。
属性动画监听:
public static interface AnimatorUpdateListener {
/**
* <p>Notifies the occurrence of another frame of the animation.</p>
*
* @param animation The animation which was repeated.
*/
void onAnimationUpdate(ValueAnimator animation);
}
public static interface AnimatorListener {
/**
* <p>Notifies the start of the animation.</p>
*
* @param animation The started animation.
*/
void onAnimationStart(Animator animation);
/**
* <p>Notifies the end of the animation. This callback is not invoked
* for animations with repeat count set to INFINITE.</p>
*
* @param animation The animation which reached its end.
*/
void onAnimationEnd(Animator animation);
/**
* <p>Notifies the cancellation of the animation. This callback is not invoked
* for animations with repeat count set to INFINITE.</p>
*
* @param animation The animation which was canceled.
*/
void onAnimationCancel(Animator animation);
/**
* <p>Notifies the repetition of the animation.</p>
*
* @param animation The animation which was repeated.
*/
void onAnimationRepeat(Animator animation);
}
AnimatorListenerAdapter是系统为AnimatorListener提供的一个适配器类便于开发者调用需要的方法
属性动画满足的条件:
1、属性动画要求动画作用的对象提供该属性的get和set方法(如果不满足直接Crash)。
2、对象的set方法对属性所做的改变必须通过某种方法反映出来,比如UI的改变(如果不满足,动画无效,不会Crash);
如果在我们开发中以上条件有一个或多个不满足怎么办呢?
官方有三种解决方案:
- 如果有权限,给你的对象加上get&set方法(逗我-_-);
- 用一个来包装对象,间接提供get&set方法(靠谱+_+);
- 采用ValueAnimator,监听动画过程,自己是实现属性的改变;
ValueAnimator:
本身不作用于任何对象,也就是说直接使用,没有任何动画效果,但它可以对一个值做动画,然后我们监听其过程,动画过程中修改对象属性值,这样就相当于我们的对象做了动画。
四、自定义View动画:
Animation是抽象类,我们只需要重写它的applyTransformation()和initialize(),在 initialize()做一些初始化操作,在applyTransformation()
进行相应的矩阵变换。
五、LayoutAnimation(布局动画):
最简单的布局动画就是在ViewGroup加上android:animateLayoutChanges=”true”
当ViewGroup添加View时候,子View会呈现逐渐显示的过度动画,这是Android默认的过度效果。
作用于ViewGroup容器,比如RecyclerView加上这样的动画,那么RecyclerView的每个item就会有一个出场效果。
用法:在res/anim文件中新建文件
<?xml version="1.0" encoding="utf-8"?>
<!--android:animationOrder="normal|random|reverse" 顺序|随机|反转
android:delay="0.5" 0.5表示子元素入场动画的周期的0.5倍 ps:周期300ms 延迟150ms
android:animation="@anim/set_animation" xml定义的动画 -->
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="0.5"
android:animationOrder="normal"
android:animation="@anim/set_animation"
/>
布局文件用法:
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layoutAnimation="@anim/anim_layout"
代码用法:
Animation animation = AnimationUtils.loadAnimation(this, R.anim.set_animation);
LayoutAnimationController controller=new LayoutAnimationController(animation);
controller.setDelay(0.5f); controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listview.setLayoutAnimation(controller);
代码写法:
ScaleAnimation animation = new ScaleAnimation(0, 1, 0, 1);
animation.setDuration(500);
LayoutAnimationController controller = new LayoutAnimationController(animation, 0.5f);
controller.setOrder(LayoutAnimationController.ORDER_RANDOM);
listView.setLayoutAnimation(controller);
六、Activity的切换动画:
overridePendingTransition(int enterAnim, int exitAnim);
enterAnim:进场动画
exitAnim :出场动画
注意要在activity执行startActivity()或者finish()之后调用
Fragment也可以添加动画FragmentTransaction中的setCustomAnimations
(@AnimRes int enter,@AnimRes int exit);
使用动画的注意事项:
1、OOM:
这个问题主要出现在帧动画,当图片资源过多且大时候极易出现OOM。所以尽量避免使用帧动画。
2、内存泄漏:
在属性动画中有一类无限循环动画,这类动画需要在Activity退出时及时停止动画,否则会导致Activity无法释放导致内存泄漏,但View动画不会。
3、兼容性问题
动画在android3.0下有兼容性问题,要做好适配
4、View动画问题
View动画是对View的影像做动画,并不是真正的改变View的状态,因此有时候出现动画完成后View无法隐藏的现象,即setVisibility(View.GONE)失效,通常这样解决:view.clearAnimation()清楚View动画即可。
5、硬件加速
使用动画时候建议开启硬件加速,提高动画的流畅性。