之前一直没有系统地学习Android中的动画,每当编码需要动画效果的时候,总是很郁闷。虽然网上已经有很多相关的教程,但是自己还是做个总结:简单简洁!
简单地说,动画就几种类型:渐变、平移、旋转等,Android中:
Tween Animation 渐变动画
包含了渐变alpha、平移translate,旋转rotate,伸缩scale,这四个还是比较常见、基础的动画
Frame Animation 帧动画
事先把所有的动画画面准备好,一帧一帧地放,相当于放电影
Property Animation 属性动画
对View的属性进行变化,达到动画效果
简单记住上面三种动画的属性就可以了,重要的是:如何加载动画。
对于渐变动画,如何将一个View(例如ImageView)实现渐变(或者缩放等)? 加载动画代码如下:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="2000"
android:fromAlpha="1.0"
android:interpolator="@android:anim/linear_interpolator"
android:toAlpha="0" />
set>
其中 duration
表示整个动画的时间,而对于一个渐变动作来说,会有一个起始透明值 fromAlpha
和结束透明值 toAlpha
,interpolator
是一个插补器,简单理解就是指定的动作效果,如实现加速、减速变化等
private ImageView photo;
...
Animation alpha = AnimationUtils.loadAnimation(MainActivity.this, R.anim.alpha); // 加载anim
photo.startAnimation(alpha); // 执行动画
以上是通过加载xml文件加载动画的,如果通过java来加载动画,则:
AlphaAnimation alpha = new AlphaAnimation(1.0f, 0);
alpha.setDuration(2000);
photo.startAnimation(alpha);
当然,有时候想同时两个动画一起加载,例如平移和渐变一起,通过 AnimationSet
类添加多个Animation实现:
// 渐变动画
Animation alpha = AnimationUtils.loadAnimation(MainActivity.this, R.anim.alpha);
alpha.setDuration(2000);
// 平移动画
TranslateAnimation translate = new TranslateAnimation(0, 160, 0, 160);
translate.setDuration(2000);
// 添加多个Animation实现同时加载多个动画
AnimationSet set = new AnimationSet(false);
set.addAnimation(alpha);
set.addAnimation(translate);
set.setFillAfter(true);
// 执行动画
photo.startAnimation(set);
对于渐变动画的属性,不同动画有不同的属性,这里列举,只需要大概记住,以后需要查找:
属性名 | 意义 |
---|---|
fromXDelta | X轴方向开始位置,可以是数值、%、%p(p表示相对于父布局) |
toXDelta | X轴方向结束位置,可以是数值、%、%p(p表示相对于父布局) |
fromYDelta | Y轴方向开始位置,可以是数值、%、%p(p表示相对于父布局) |
toYDelta | Y轴方向结束位置,可以是数值、%、%p(p表示相对于父布局) |
属性名 | 意义 |
---|---|
fromXScale | 起始的X方向上相对自身的缩放比例,浮点数,1.0表示本身 |
toXDelta | 结束时的X方向上相对自身的缩放比例,浮点数,1.0表示本身 |
fromYDelta | 起始的Y方向上相对自身的缩放比例,浮点数,1.0表示本身 |
toYDelta | 结束时的X方向上相对自身的缩放比例,浮点数,1.0表示本身 |
pivotX | 缩放时起点的X轴坐标,可以是数值、%、%p |
pivotY | 缩放时起点的Y轴坐标,可以是数值、%、%p |
属性名 | 意义 |
---|---|
fromAlpha | 动画开始时的透明度,浮点数,1.0表示不透明 |
toAlpha | 动画结束时的透明度,浮点数,1.0表示不透明 |
属性名 | 意义 |
---|---|
fromDegrees | 动画开始时旋转的角度位置,正代表顺时针度数 |
toDegrees | 动画结束时旋转的角度位置,正代表顺时针度数 |
pivotX | 旋转开始时的X轴坐标,可以是数值、%、%p |
pivotY | 旋转开始时的Y轴坐标,可以是数值、%、%p |
属性名 | 意义 |
---|---|
duration | 动画持续时间,以毫秒为单位 |
fillAfter | 是否在动画结束时保持动画最后时的状态 |
fillBefore | 是否在动画结束时还原动画最初时的状态 |
repeatCount | 重复次数 |
repeatMode | 有reverse和restart两个值,reverse表示倒序回放,restart表示重新放一遍 |
interpolator | 指定的动作效果,例如动作速度、弹跳等 |
属性名 | 意义 |
---|---|
linear_interpolator | 以常量速率改变 |
decelerate_interpolator | 动画由快变慢 |
cycle_interpolator | 动画循环播放特定的次数,速率改变沿着正弦曲线 |
bounce_interpolator | 动画结束时弹起 |
overshoot_interpolator | 向前甩一定值后再回到原来位置 |
总结: 以上就是渐变动画的加载,相对还是比较简单,通过编写xml文件,然后通过 AnimationUtils
加载动画,或者new一个Animation的类对象(如TranslateAnimation),最后通过 startAnimation()
方法执行动画。
帧动画需要实现提供对应动画“每一帧”的画面,执行动画的时候,将每一个动画播放出来。
如何加载帧动画?——通过 AnimationDrawable
加载,需要实现在drawables编写对应的xml文件: /res/drawable/frame.xml
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/btn_star_off_disabled_holo_dark" android:duration="500" />
<item android:drawable="@drawable/btn_star_off_disabled_holo_light" android:duration="500" />
<item android:drawable="@drawable/btn_star_off_focused_holo_dark" android:duration="500" />
<item android:drawable="@drawable/btn_star_off_focused_holo_light" android:duration="500" />
animation-list>
其中, oneshot
为true表示动画是只播放一次,并停在最后一帧,false则动画循环播放;该动画共4帧,每一帧持续500ms。
接下来通过 AnimationDrawable
来执行动画:
AnimationDrawable frame = (AnimationDrawable) getResources().getDrawable(R.drawable.frame);
photo.setBackgroundDrawable(anim);
frame.start();
我觉得后面这文章的属性动画讲得很好:Android属性动画深入分析:让你成为动画牛人
属性动画主要针对属性进行变换从而实现动画效果,例如将ImageView的宽度增加(针对View的width)、位置的改变(针对View 的translateX)、透明度改变等,先大概说如何加载属性动画。
// 获取mView的translationX属性,将translationX属性从0变换到500
ObjectAnimator transAnim = ObjectAnimator.ofFloat(mView, "translationX", 0, 500);
transAnim.setDuration(200);
transAnim.start(); //执行动画
原理
属性动画要求动画作用的对象提供该属性的get和set方法,属性动画根据你传递的初始值和最终值,以动画的效果多次去调用set方法,每次传递给set方法的值都不一样,确切来说是随着时间的推移,所传递的值越来越接近最终值。当你对view的属性xxx做动画,如果想让动画生效,要同时满足两个条件:
对任何属性执行动画
Android中有一些view的属性并没有提供getter或setter,或者setter或getter并非直接操作view的对应属性,例如TextView的setWidth()和getWidth()并非直接操作width和height,所以需要通过获取其LayoutParams来改变其width和height属性。
参照上文链接的文章,实现一个 ViewWrapper
类来封装我们的View的各个属性,从而能够通过属性动画来加载动画:
public static class ViewWrapper {
private View targetView;
public ViewWrapper(View targetView) {
this.targetView = targetView;
}
public int getWidth() {
return targetView.getLayoutParams().width;
}
public void setWidth(int width) {
targetView.getLayoutParams().width = width;
targetView.requestLayout();
}
public int getHeight() {
return targetView.getLayoutParams().height;
}
public void setHeight(int height) {
targetView.getLayoutParams().height = height;
targetView.requestLayout();
}
public float getTranslationX() {
return targetView.getTranslationX();
}
public void setTranslationX(float translationX) {
targetView.setTranslationX(translationX);
}
public float getTranslationY() {
return targetView.getTranslationY();
}
public void setTranslationY(float translationY) {
targetView.setTranslationY(translationY);
}
}