Android 的动画分为三种:View 动画,帧动画,属性动画。View 动画通过对场景里的对象不断做图像变换从而产生动画效果,是一种渐进式动画,并且View动画支持自定义。帧动画通过顺序播放一系列图像从而产生动画效果。属性动画通过动态的改变对象的属性从而达到动画效果。
View 动画
- View 动画的作用对象是 View,它支持四种动画效果,分别是平移动画、缩放动画、旋转动画和透明度动画,分别对应 Animation 的四个子类:TranslateAnimation、ScaleAnimation、RotateAnimation 和 AlphaAnimation,四种动画既可以用 XML 定义也可以有代码动态创建,建议采用 XML 来定义,路径为res/anim/filename.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true" 是否和集合共享同一个插值器
android:fillAfter="true" 动画结束后是否停留在结束位置
> <set>标签代表集合,对应AnimationSet类
<alpha
android:duration="5000" 动画的持续时间
android:fromAlpha="0.1" 表示透明度的起始值
android:toAlpha="1" 表示透明度的结束值
/>
<scale
android:duration="5000"
android:fromXScale="0.5" 水平方向缩放的起始值
android:toXScale="1.2" 水平方向缩放的结束值
android:fromYScale="0.5" 竖直方向缩放的起始值
android:toYScale="1.2" 竖直方向缩放的结束值
android:pivotX="0" 缩放的轴点的 X 坐标,默认中心
android:pivotY="30" 缩放的轴点的 y 坐标,默认中心
/>
<translate
android:duration="5000"
android:fromXDelta="0" 表示 x 的起始坐标
android:toXDelta="20" 表示 y 的结束值
android:fromYDelta="0" 表示 y 的起始坐标
android:toYDelta="20" 表示 y 的结束值
/>
<rotate
android:duration="5000"
android:fromDegrees="0" 旋转的开始的角度
android:toDegrees="180" 旋转的结束的角度
android:pivotX="10" 旋转的轴点的 x 坐标,默认中心
android:pivotY="10"/> 旋转的轴点的 y 坐标,默认中心
</set>
帧动画
- 帧动画是顺序播放的一组预先定义好的图片,类似于电影播放。不同于 View 动画,系统提供另外一个类 AnimationDrawable 来使用帧动画。
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false"> 表示是否只展示一遍
<item android:drawable="@mipmap/image" android:duration="500"/>
<item android:drawable="@mipmap/image1" android:duration="500"/>
</animation-list>
Button btn_frame = findViewById(R.id.btn_frame);
btn_frame.setBackgroundResource(R.drawable.frame_animation);
AnimationDrawable drawable = (AnimationDrawable) btn_frame.getBackground();
drawable.start();
View 动画的特殊使用场景
- LayoutAnimation 作用于 ViewGroup,为 ViewGroup 指定一个动画,当它的子元素出场时会具有这种动画效果,效果常常被用在 ListView 上,每个 item 都以一定的动画形式出现。
可以在 XML 中指定 LayoutAnimation 外,还可以通过 LayoutAnimationController 实现,下面是代码实现。
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
MainActivity.this, android.R.layout.simple_list_item_1, data);
ListView listView = (ListView) findViewById(R.id.listview);
Animation animation1 = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation1);
controller.setDelay(0.5f); //子动画延迟,如果周期为1000,那么每个元素延迟为500
controller.setOrder(LayoutAnimationController.ORDER_NORMAL); //子动画显示顺序
listView.setLayoutAnimation(controller);
listView.setAdapter(adapter);
在 anim 文件夹下定义动画 anim_item.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:shareInterpolator="true">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"/>
<translate
android:fromXDelta="500"
android:toXDelta="0"/>
</set>
- Activity 的切换效果,这个效果我们可以自定义,这个方法必须在 startAcivity(Intent) 或者 finish() 之后调用才能生效。
启动 Activity 时
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);
退出 Activity 时
public void finish() {
super.finish();
overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);
}
属性动画
- 属性动画可以对任意对象的属性进行动画而不仅仅是 View,动画默认时间间隔300ms,默认帧率 10ms/帧。效果是在一定的时间间隔内完成对象从一个属性值到另外一个属性值的改变。比较常见的动画类是: ValueAnimator,ObjectAnimator 和 AnimatorSet,其中 ObjectAnimator 继承自 ValueAnimtor,AnimatorSet 是动画集合。
(1)改变一个对象的 TranslationY 属性,平移一段距离。
ObjectAnimator.ofFloat(myObject,"translationY",btnDown.getHeight()).start();
(2)改变一个对象的背景色属性,颜色由红变蓝。
ValueAnimator colorAnim = ObjectAnimator.ofInt(myObject,
"backgroundColor", 0xffff8080, 0xff8080ff);
colorAnim.setDuration(3000);
colorAnim.setEvaluator(new ArgbEvaluator());
colorAnim.setRepeatCount(ValueAnimator.INFINITE);
colorAnim.setRepeatMode(ValueAnimator.REVERSE);
colorAnim.start();
(3)动画集合,5s 内对 View 的旋转,平移,缩放和透明度都进行了改变。
AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(ivSet,"rotationX",0,360),
ObjectAnimator.ofFloat(ivSet,"rotationY",0,180),
ObjectAnimator.ofFloat(ivSet,"rotation",0,-90),
ObjectAnimator.ofFloat(ivSet,"translationX",0,90),
ObjectAnimator.ofFloat(ivSet,"translationY",0,90),
ObjectAnimator.ofFloat(ivSet,"scaleX",1,1.5f),
ObjectAnimator.ofFloat(ivSet,"scaleY",1,0.5f),
ObjectAnimator.ofFloat(ivSet,"alpha",1,0.25f,1)
);
set.setDuration(5000).start();
属性动画除了通过代码实现以外,还可以通过 XML 来定义,需要定义在 res/animator/目录下,实际开发中建议采用代码来实现属性动画,因为很多时候一个属性的起始值是无法提前确定,必须通过代码动态创建属性动画。
对任意属性做动画
- 提出问题:改变 Button 的宽度,如果用 View 动画 Button 的背景以及上面的文字会被拉伸,甚至有可能 Button 会超出屏幕,使用属性动画可以解决此问题。
- 属性动画原理:属性动画要求动画作用的对象提供该属性的 get 和 set 方法,根据外界传递的属性值,以动画的效果多次调用 set 方法,如果让动画生效,要同时满足两个条件。
- object 必须提供 setAbc 方法,如果动画的时候没有传递初始值,那么还要提供 getAbc 方法,因为系统会去 abc 属性的初始值。
- object 的 setAbc 对属性 abc 所做的改变必须能够通过某种方法反应出来,比如会带来 UI 改变之类的。
- Button 继承 TextView,TextView 的 getWidth 方法获取的是 View 宽度,而setWidth 是设置 TextView 的最大宽度和最小宽度。动画不生效的原因是只满足了条件 1,而且未满足条件 2。
- 解决常用方法,用一个类包装原始对象,间接为其提供 get 和 set 方法。示例代码
btn_attr.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
performAnimate();
}
});
private void performAnimate() {
ViewWrapper wrapper = new ViewWrapper(btn_attr);
ObjectAnimator.ofInt(wrapper,"width",500).
setDuration(5000).start();
}
private static class ViewWrapper {
private View mTarget;
public ViewWrapper(View target) {
mTarget = target;
}
public int getWidth() {
return mTarget.getLayoutParams().width;
}
public void setWidth(int width) {
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
使用动画的注意事项
- OOM问题
这个问题主要出现在帧动画当中,当图片数量过多或较大时就极易出现 OOM,开发中要注意,尽量避免使用帧动画。 - 内存泄漏
在属性动画中有一类无限循环的功能,这类动画需要在 Activity 退出时及时停止,否则将导致 Activity 无法释放从而造成内存泄漏,通过验证后发现 View 动画并不存在此问题。 - 兼容性问题
动画在 3.0 以下系统上有兼容性问题,在某些特殊场景可能无法正常工作,因此要做好适配工作。 - View 动画的问题
View 动画是对 View 的影像做动画,并不是真正改变 View 的状态,因此有时候会出现属性动画完成后 View 无法隐藏的现象,即 setVisibility(View.GONE)失效了,这个时候只需要调用 View.clearAnimation() 清除 View 动画即可解决此问题。 - 不要使用px
在进行动画的过程中,要尽量使用 dp,使用 px 会导致不同的设备上有不同的效果。 - 动画元素的交互
将 View 移动(平移)后,在 Android 3.0 以前的系统上,不管是 View 动画还是属性动画,新位置无法触发单击事件,同时,老位置仍然可以触发单击事件。尽管 View 已经在视觉上已经不存在了,将 View 移回原位置以后,原位置单击事件继续生效。从 3.0 开始,属性动画的单击事件触发位置为移动后的位置,但是 View 动画仍然在原位置。 - 硬件加速
在使用动画的过程中,建议开启硬件加速,这样会提高动画的流畅性。