一.VIEW动画
-
view动画的种类
-
自定义view动画
-
view动画的特殊类型
二.帧动画
三.属性动画
- 属性动画的分类
- 和View动画的区别
- 插值器与估值器
- 属性动画的使用
- 属性动画的监听器
- 属性动画工作原理
- 属性动画的注意事项
四.动画注意事项
一.View动画
1.view动画种类
(1)分类
注意:view动画不改变View的属性,点击事件等任在原位置响应。
(2)view动画的实现(推荐使用xml文件实现)
实现方法1:xml文件实现,activity引用
xml文件(路径为res/anim)
<?xml version="1.0" encoding="utf-8"?>
<set //动画集合
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="your interpolator"//插值器,系统有默认值,详见后面
android:shareInterpolator="true" //集合的动画是否和动画共享一个插值器
android:fillAfter="true"> //动画完成后是否停留在结束位置
<translate //平移
android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float"/>
<scale //缩放
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float" //旋转的中心点x,默认为元素中心
android:pivotY="float"/>
<rotate //旋转
android:fromDegrees="float"
android:toDegrees="float"
android:pivotY="float" //缩放中心点
android:pivotX="float"/>
<alpha
android:fromAlpha="float"
android:toAlpha="float"/>
</set>
java中引用
Animation animation = AnimationUtils.loadAnimation(this, R.anim.XXX);
mView.startAnimation(animation);
实现方法二:java代码创建
设置对应动画的参数,构造对象,再调用即可
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
alphaAnimation.setDuration(2000);
mImageView.startAnimation(alphaAnimation);
2.自定义View动画
四种动画不能满足需要,自定义动画。
步骤:继承Animation->重写initialize()和applyTransformation()方法:initialize()用于初始化;applyTransformation()用于进行矩阵变换
3.View动画的特殊类型
(1)LayoutAnimation
- 作用于ViewGroup,为ViewGroup制定一个动画,这样当他的子元素出场时就会有设置的动画效果,可用于ListView等
实现方法一:通过xml文件实现,布局.xml文件中引用
res/anim/anim_layout.xml
<layoutAnimation
xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/anim_item" //指定具体动画
android:delay="0.5"
android:animationOrder="normal">//子元素动画的播放顺序:
//normal (正常顺序)、random(随机顺序)、reverse(倒序)。
</layoutAnimation>
res/anim/anim_item.xml
<?xml version="1.0" encoding="utf-8"?>
<set //动画集合
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:shareInterpolator="true">
<translate //平移
android:fromXDelta="111"
android:toXDelta="0" />
<alpha
android:fromAlpha="0"
android:toAlpha="1"/>
</set>
布局文件中引用(假设为ListView)
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutAnimation="@anim/anim_layout"/>
实现方法2:java代码创建
Animation animation = AnimationUtils.loadLayoutAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);//对应android:animation属性
controller.setDelay(0.5);//对应android:delay属性
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);//对应android:animationOrder属性
listView.setLayoutAnimation(controller);//对应android:layoutAnimation属性
(2)Activity的切换效果
- 该文件创建在res/anim/下
- Activity默认是有切换效 果的,若需要自定义切换效果,需要用到overridePendingTransition(int inAnim, int outAnim)方法。
- 该方法调用在startActivity()或finish()之后才生效。
startActivity(intent);
//(进入动画.xml,退出动画.xml)
overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim);
二.逐帧动画
1.定义:
帧动画也是View动画的一种,它会按照顺序播放一组预先定义好的图片。对应类AnimationDrawable。
注意:逐帧动画不能使用尺寸过大的图片,否则会造成OOM
2.逐帧动画的实现
方法一:xml定义(位于res/drawable/下),java代码中作为view的背景引入
xml文件
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">//是否执行一次
<item
android:drawable="@drawable/xxx1" //图片源
android:duration="500"/>//持续时间
<item
android:drawable="@drawable/xxx2"
android:duration="500"/>
<item
android:drawable="@drawable/xxx3"
android:duration="500"/>
<item
android:drawable="@drawable/xxx4"
android:duration="500"/>
</animation-list>
activity
mView.setBackgroundResource(R.drawable.XXX);
AnimationDrawable animationDrawable = (AnimationDrawable)mView.getBackground();
animationDrawable.start();
方法二:java代码动态创建
//和上述xml定义方法的效果相同
AnimationDrawable ad = new AnimationDrawable();//1.创建AnimationDrawable对象
for (int i = 0; i < 4; i++) {//2.添加Drawable对象及其持续时间
Drawable drawable = getResources().getDrawable(getResources().getIdentifier("xxx" + i, "drawable", getPackageName()));
ad.addFrame(drawable, 500);
}
ad.setOneShot(false);//3.设置是否执行一次
mView.setBackgroundResource(ad);//4.将帧动画作为view背景
ad.start();//5.播放动画
三.属性动画
1.属性动画分类
根节点<set>对应AnimatorSet类
点<objectAnimator>对应ObjectAnimator类
<animator>对应ValueAnimator类
两个子节点区别:
- ValueAnimator 类是先改变值,然后手动赋值给对象的属性从而实现动画;是间接对对象属性进行操作;(手动赋值的过程通过监听动画,然后改变对象属性,重绘来实现,需要自己实现)
- ObjectAnimator 类是先改变值,然后自动赋值给对象的属性从而实现动画;是直接对对象属性进行操作
2.和View动画的区别
3.插值器与估值器
(1)插值器
- 作用:根据时间流逝的百分比计算出当前属性值改变的百分比。确定了动画效果变化的模式,如匀速变化、加速变化等等。
- 常用的系统内置插值器:
- 线性插值器(LinearInterpolator):匀速动画
- 加速减速插值器(AccelerateDecelerateInterpolator):动画两头慢中间快
- 减速插值器(DecelerateInterpolator):动画越来越慢
- 可针对的对象
- View动画:插值器对应的属性是android:interpolator。
- 属性动画:是实现非匀速动画的重要手段。
- 自定义插值器方法:实现 Interpolator (view动画)/ TimeInterpolator(属性动画)接口 ,然后复写getInterpolation()。
(2)估值器(TypeEvaluator)
- 作用:根据当前属性改变的百分比计算出改变后的属性值。
- 常用的系统内置的估值器:
-
- 整形估值器(IntEvaluator)
- 浮点型估值器(FloatEvaluator)
- Color属性估值器(ArgbEvaluator)
- 针对于属性动画,View动画不需要类型估值器。是属性动画实现非匀速动画的重要手段。
- 自定义估值器方法:实现TypeEvaluator接口,然后复写evaluate()。
4.属性动画的实现
(1)xml中实现(位于res/animator/),java中引用
res/animator/propertyName.xml(ValueAnimator)
// ObjectAnimator 采用<animator> 标签
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="1" // 初始值
android:valueTo="0" // 结束值
android:valueType="floatType" // 变化值类型 :floatType & intType
android:propertyName="alpha" // 对象变化的属性名称
/>
java代码中引用
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.propertyName);
// 载入XML动画
animator.setTarget(view);
// 设置动画对象
animator.start();
// 启动动画
(2)java代码动态生成
ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String property, float ....values);
// ofFloat()作用有两个
// 1. 创建动画实例
// 2. 参数设置:参数说明如下
// Object object:需要操作的对象
// String property:需要操作的对象的属性
// float ....values:动画初始值 & 结束值(不固定长度)
// 若是两个参数a,b,则动画效果则是从属性的a值到b值
// 若是三个参数a,b,c,则则动画效果则是从属性的a值到b值再到c值
// 以此类推
// 至于如何从初始值 过渡到 结束值,同样是由估值器决定,此处ObjectAnimator.ofFloat()是有系统内置的浮点型估值器FloatEvaluator,同ValueAnimator讲解
anim.setDuration(500);
// 设置动画运行的时长
anim.setStartDelay(500);
// 设置动画延迟播放时间
anim.setRepeatCount(0);
// 设置动画重复播放次数 = 重放次数+1
// 动画播放次数 = infinite时,动画无限重复
anim.setRepeatMode(ValueAnimator.RESTART);
// 设置重复播放动画模式
// ValueAnimator.RESTART(默认):正序重放
// ValueAnimator.REVERSE:倒序回放
animator.start();
// 启动动画
5.属性动画的监听器
属性动画主要使用两个接口:AnimatorUpdateListener&AnimatorListener来监听动画的播放过程。
- AnimatorListener :监听动画的开始、结束、取消以及重复播放。
- 为方便开发,系统提供了AnimatorListenerAdapter类,它是AnimatorListener的适配器,如此可有选择复写上述四个方法。
- AnimatorUpdateListener :监听整个动画过程。每播放一帧onAnimationUpdate()就会被调用一次
public static interface AnimatorListener {
void onAnimationStart(Animator animation); //动画开始
void onAnimationEnd(Animator animation); //动画结束
void onAnimationCancel(Animator animation); //动画取消
void onAnimationRepeat(Animator animation); //动画重复播放
}
public interface AnimatorUpdateListener {
void onAnimationUpdate(ValueAnimator var1);//在属性动画的属性值变化是回调。
}
6.属性动画的工作原理
在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果。(通过反射调用get/set方法)
- step1:创建属性动画时,若未设置属性的初始值,则系统会通过该属性的get()方法获取初始值。故属性动画要求必须提供属性的get()方法。
- step2: 在动画播放的过程中,利用时间插值器和类型估值器获取改变后的属性值。
- step3:将改变后的属性值通过set()方法设置到对象中。故属性动画要求必须提供属性的set()方法。
7.属性动画注意事项
由于需要调用对象的get/set方法来动态改变对象的属性,所以对objec的abc属性做动画,想要让动画生效必须满足两个条件:
- object必须提供setABC方法,如果动画的时候没有传递初始值,那么还要提供getABC方法,系统会通过该属性的get()方法获取初始值(如果这条不满足,程序直接crash)
- obje的setABC对属性abc做出的改变必须能够以某种方式反映出来,比如UI变化(这条不满足,不会crash但是动画没有效果)
例子:
对Button的的width属性做动画,没有相应效果(可以验证)。
原因:Button的setWidth是继承自TextView的方法,设置的是TextView的最大宽度,不是设置View的宽,不满足第二条。
解决办法:
- 给你的对象加上get/set方法(Android SDK内部实现,所以这个方法无效)
- 用一个类包装原始对象,间接为其提供get和set方法
- 采用ValueAnimator,监听动画过程,自己实现属性的改变
(2)用一个类包装原始对象,间接为其提供get和set方法
private void performAnimate() {
ViewWrapper viewWrapper = new ViewWrapper(btn);
ObjectAnimator.ofInt(viewWrapper, "width", 500).setDuration(1000).start();
}
private static class ViewWrapper {
private View mTarget;
public ViewWrapper(View mTarget) {
this.mTarget = mTarget;
}
public int getWidth() {
return mTarget.getLayoutParams().width;
}
public void setWidth(int width) {
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
(3)采用ValueAnimator
private void performAnimator(final View target, final int start, final int end) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//持有一个IntEvaluator对象,方便下面估值的时候使用
private IntEvaluator mEvaluator = new IntEvaluator();
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获得当前动画的进度值,整形1-100之间
int currentValue = (int) animation.getAnimatedValue();
//获得当前进度占整个动画之间的比例,浮点0-1之间
float fraction = animation.getAnimatedFraction();
//直接使用整形估值器,通过比例计算宽度,然后再设置给按钮
target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);
target.requestLayout();
}
});
valueAnimator.setDuration(5000).start();
}
四.动画注意事项
- 1.OOM问题
这个问题主要还是帧动画中,当图片过多的时候就OOM了,这个在实际的开发中尤其注意,尽量避免使用帧动画
- 2.内存泄漏
在属性动画中有一类无限循环的动画,如果你在activity退出后不停止的话,可能就会存在这个问题了
- 3.兼容性问题
动画在3.0以下的系统上有缺陷,最好做好适配工作
- 4.View动画的问题
view动画死对view的影像做动画,并不是真正的改变view的状态,因此有时候会出现完成后view无法隐藏的现象,即setVisibility(View.GONE),这个时候只要调用clearAnimation清除动画即可
- 5.不要使用PX
在进行动画的过程,要尽量使用dp,使用px会导致适配问题
- 6.动画元素的交互
将view移动后,在3.0以前的系统,不管是view动画还是属性动画,新位置都无法调用单机事件,同时老位置却可以,从3.0之后,属性动画的点击事件触发位置为移动后的位置,但是view动画仍然在原位置。
- 7.硬件加速
使用动画的过程,建议开启硬件加速,这样会提高动画的流畅性 动画