安卓动画总结
补间动画(Tween Animation)
开发者无需定义动画的每一帧,只需要定义开始和结束的关键帧和动画变化的时间和方式,剩下的交给安卓系统进行计算,通过在两个关键帧之间插入渐变值来实现平滑过渡
补间动画主要包括4种基本效果:透明度变化Alpha,大小变化Scale,位移变化Translate,旋转变化Rotate,四种变化可以动态组合,可以使用xml定义也可以直接使用代码定义
插值器(Interpolator)
前面说到安卓系统会在补间动画的开始和结束的关键帧之间插入渐变值,这个值的计算依据就是插值器
插值器有很多种,可以实现诸如加速,减速,均速,抛物线等多种变化,如下:
java类 | xml id值 | 描述 |
---|---|---|
AccelerateDecelerateInterpolator | @android:anim/accelerate_decelerate_interpolator | 动画始末速率较慢,中间加速 |
AccelerateInterpolator | @android:anim/accelerate_interpolator | 动画开始速率较慢,之后慢慢加速 |
AnticipateInterpolator | @android:anim/anticipate_interpolator | 开始的时候从后向前甩 |
AnticipateOvershootInterpolator | @android:anim/anticipate_overshoot_interpolator | 类似上面AnticipateInterpolator |
BounceInterpolator | @android:anim/bounce_interpolator | 动画结束时弹起 |
CycleInterpolator | @android:anim/cycle_interpolator | 循环播放速率改变为正弦曲线 |
DecelerateInterpolator | @android:anim/decelerate_interpolator | 动画开始快然后慢 |
LinearInterpolator | @android:anim/linear_interpolator | 动画匀速改变 |
OvershootInterpolator | @android:anim/overshoot_interpolator | 向前弹出一定值之后回到原来位置 |
PathInterpolator | 新增,定义路径坐标后按照路径坐标来跑。 |
<set android:interpolator="@android:anim/accelerate_interpolator">
...
</set>
共有属性
xml属性 | java方法 | 解释 |
---|---|---|
android:detachWallpaper | setDetachWallpaper(boolean) | 是否在壁纸上运行 |
android:duration | setDuration(long) | 动画持续时间,毫秒为单位 |
android:fillAfter | setFillAfter(boolean) | 控件动画结束时是否保持动画最后的状态 |
android:fillBefore | setFillBefore(boolean) | 控件动画结束时是否还原到开始动画前的状态 |
android:fillEnabled | setFillEnabled(boolean) | 与android:fillBefore效果相同 |
android:interpolator | setInterpolator(Interpolator) | 设定插值器(指定的动画效果,譬如回弹等) |
android:repeatCount | setRepeatCount(int) | 重复次数 |
android:repeatMode | setRepeatMode(int) | 重复类型有两个值,reverse表示倒序回放,restart表示从头播放 |
android:startOffset | setStartOffset(long) | 调用start函数之后等待开始运行的时间,单位为毫秒 |
android:zAdjustment | setZAdjustment(int) | 表示被设置动画的内容运行时在Z轴上的位置(top/bottom/normal),默认为normal |
透明度动画(AlphaAnimation)
xml写法:
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromAlpha="1.0"
android:toAlpha="0.1" />
<!--0.0完全透明,1.0完全不透明-->
xml属性 | java方法 | 解释 |
---|---|---|
android:fromAlpha | AlphaAnimation(float fromAlpha, …) | 动画开始的透明度(0.0到1.0,0.0是全透明,1.0是不透明) |
android:toAlpha | AlphaAnimation(…, float toAlpha) | 动画结束的透明度,同上 |
代码写法:
//透明度动画
AlphaAnimation alphaAnimation=new AlphaAnimation(0,1);
alphaAnimation.setDuration(1000);//动画执行时间
alphaAnimation.setFillAfter(true);//动画执行完成之后保持动画最后的状态
tv_test.setAnimation(alphaAnimation);
AlphaAnimation的构造函数只有2个参数,分别是开始时的透明度和结束时的透明度
/**
* Constructor to use when building an AlphaAnimation from code
*
* @param fromAlpha Starting alpha value for the animation, where 1.0 means
* fully opaque and 0.0 means fully transparent.
* @param toAlpha Ending alpha value for the animation.
*/
public AlphaAnimation(float fromAlpha, float toAlpha) {
mFromAlpha = fromAlpha;
mToAlpha = toAlpha;
}
不同的插值器对实际效果的影响如下:
缩放动画(ScaleAnimation)
xml写法:
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromYScale="0.2"
android:fromXScale="0.2"
android:toXScale="1.5"
android:toYScale="1.5"
android:pivotX="50%"
android:pivotY="50%">
</scale>
xml属性 | java方法 | 解释 |
---|---|---|
android:fromXScale | ScaleAnimation(float fromX, …) | 初始X轴缩放比例,1.0表示无变化 |
android:toXScale | ScaleAnimation(…, float toX, …) | 结束X轴缩放比例 |
android:fromYScale | ScaleAnimation(…, float fromY, …) | 初始Y轴缩放比例 |
android:toYScale | ScaleAnimation(…, float toY, …) | 结束Y轴缩放比例 |
android:pivotX | ScaleAnimation(…, float pivotX, …) | 缩放起点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点) |
android:pivotY | ScaleAnimation(…, float pivotY) | 缩放起点Y轴坐标,同上规律 |
代码写法:
//缩放动画
ScaleAnimation scaleAnimation=new ScaleAnimation(0.2f,1.5f,/**X坐标的起始尺寸和结束尺寸*/
0.2f,1.5f,/**Y坐标的起始尺寸和结束尺寸*/
Animation.RELATIVE_TO_SELF,0.5f,/**动画缩放位置为X轴中心点*/
Animation.RELATIVE_TO_SELF,0.5f);/**动画缩放位置为Y轴中心点*/
scaleAnimation.setDuration(1000);//动画执行时间
scaleAnimation.setFillAfter(true);
tv_test.setAnimation(scaleAnimation);
public ScaleAnimation(float fromX, float toX, float fromY, float toY,
int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
...
}
这里的pivotXValues表示的是动画在X轴的伸缩模式,也就是中心点相对于那个物件,取值是Animation.ABSOLUTE,Animation.RELATIVE_TO_SELF和Animation.RELATIVE_TO_PARENT,通常使用Animation.RELATIVE_TO_SELF,即相对于自身
运行效果如下:
位移动画(TranslateAnimation)
xml写法:
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromYDelta="0"
android:fromXDelta="0"
android:toXDelta="0"
android:toYDelta="200">
</translate>
xml属性 | java方法 | 解释 |
---|---|---|
android:fromXDelta | TranslateAnimation(float fromXDelta, …) | 起始点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点) |
android:fromYDelta | TranslateAnimation(…, float fromYDelta, …) | 起始点Y轴从标,同上规律 |
android:toXDelta | TranslateAnimation(…, float toXDelta, …) | 结束点X轴坐标,同上规律 |
android:toYDelta | TranslateAnimation(…, float toYDelta) | 结束点Y轴坐标,同上规律 |
代码写法:
//位移动画
TranslateAnimation translateAnimation=new TranslateAnimation(0,0,0,200);
translateAnimation.setDuration(1000);//动画执行时间
translateAnimation.setFillAfter(true);
tv_test.setAnimation(translateAnimation);
TranslateAnimation的构造函数有两种,一种直接设置起始坐标和结束坐标即可,如下
/**
* Constructor to use when building a TranslateAnimation from code
*
* @param fromXDelta Change in X coordinate to apply at the start of the
* animation
* @param toXDelta Change in X coordinate to apply at the end of the
* animation
* @param fromYDelta Change in Y coordinate to apply at the start of the
* animation
* @param toYDelta Change in Y coordinate to apply at the end of the
* animation
*/
public TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta) {
mFromXValue = fromXDelta;
mToXValue = toXDelta;
mFromYValue = fromYDelta;
mToYValue = toYDelta;
mFromXType = ABSOLUTE;
mToXType = ABSOLUTE;
mFromYType = ABSOLUTE;
mToYType = ABSOLUTE;
}
另一种则需要给每个参数都指明模式,比较麻烦
public TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
int fromYType, float fromYValue, int toYType, float toYValue) {
mFromXValue = fromXValue;
mToXValue = toXValue;
mFromYValue = fromYValue;
mToYValue = toYValue;
mFromXType = fromXType;
mToXType = toXType;
mFromYType = fromYType;
mToYType = toYType;
}
演示效果如下:
旋转动画(RotateAnimation)
xml写法:
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromDegrees="0"
android:pivotY="50%"
android:pivotX="50%"
android:toDegrees="360"
>
</rotate>
xml属性 | java方法 | 解释 |
---|---|---|
android:fromDegrees | RotateAnimation(float fromDegrees, …) | 旋转开始角度,正代表顺时针度数,负代表逆时针度数 |
android:toDegrees | RotateAnimation(…, float toDegrees, …) | 旋转结束角度,正代表顺时针度数,负代表逆时针度数 |
android:pivotX | RotateAnimation(…, float pivotX, …) | 缩放起点X坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点) |
android:pivotY | RotateAnimation(…, float pivotY) | 缩放起点Y坐标,同上规律 |
代码写法:
//旋转动画
RotateAnimation rotateAnimation=new RotateAnimation(0,360,0.5f,0.5f);
rotateAnimation.setDuration(1000);//动画执行时间
rotateAnimation.setFillAfter(true);
tv_test.setAnimation(rotateAnimation);
构造函数有三种,如下
public RotateAnimation(float fromDegrees, float toDegrees) {
}
public RotateAnimation(float fromDegrees, float toDegrees, float pivotX, float pivotY) {
}
public RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue,
int pivotYType, float pivotYValue) {
}
效果图:
逐帧动画(Fram Animation)
它允许你实现像播放幻灯片一样的效果,这种动画的实质其实是Drawable,所以这种动画的XML定义方式文件一般放在res/drawable/目录下。
我们依旧可以使用xml或者java方式实现帧动画。但是依旧推荐使用xml,具体如下:
<animation-list>
必须是根节点,包含一个或者多个<item>
元素,属性有:
- android:oneshot true代表只执行一次,false循环执行。
-
<item>
类似一帧的动画资源。
<item>
animation-list的子项,包含属性如下:
- android:drawable 一个frame的Drawable资源。
- android:duration 一个frame显示多长时间。
<?xml version="1.0" encoding="utf-8"?>
<animation-listxmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot=["true" | "false"] >
<item
android:drawable="@[package:]drawable/drawable_resource_name"
android:duration="integer" />
</animation-list>
代码写法,使用较少:
//逐帧动画
AnimationDrawable animationDrawable=new AnimationDrawable();
for(int i=1;i<5;i++){
int id=getResources().getIdentifier("img_"+i,"drawable",getPackageName());
Drawable drawable=getResources().getDrawable(id);
animationDrawable.addFrame(drawable,120);
}
imageview.setBackgroundDrawable(animationDrawable);
animationDrawable.setOneShot(false);
定义好动画之后可以在合适的时机控制动画的播放和停止,伪代码如下:
AnimationDrawable animationDrawable1= (AnimationDrawable) imageview.getBackground();
animationDrawable1.start();//启动
animationDrawable1.stop();//停止
特别注意,AnimationDrawable的start()方法不能在Activity的onCreate方法中调运,因为AnimationDrawable还未完全附着到window上,所以最好的调运时机是onWindowFocusChanged()方法中。
属性动画(Property Animation)
在使用属性动画之前先来看几个常用的View属性成员:
- translationX,translationY:控制View的位置,值是相对于View容器左上角坐标的偏移。
- rotationX,rotationY:控制相对于轴心旋转。
- x,y:控制View在容器中的位置,即左上角坐标加上translationX和translationY的值。
- alpha:控制View对象的alpha透明度值。
这几个常用的属性相信大家都很熟悉,接下来的属性动画我们就从这里展开。
Android 3.0以后引入了属性动画,属性动画可以轻而易举的实现许多View动画做不到的事,上面也看见了,View动画无非也就做那几种事情,别的也搞不定,而属性动画就可以的,譬如3D旋转一张图片。其实说白了,你记住一点就行,属性动画实现原理就是修改控件的属性值实现的动画。以下是属性动画的实现子类
java类名 | xml关键字 | 描述信息 |
---|---|---|
ValueAnimator |
<animator> 放置在res/animator/目录下 |
在一个特定的时间里执行一个动画 |
TimeAnimator | 不支持/点我查看原因 | 时序监听回调工具 |
ObjectAnimator |
<objectAnimator> 放置在res/animator/目录下 |
一个对象的一个属性动画 |
AnimatorSet |
<set> 放置在res/animator/目录下 |
动画集合 |
先从简单的开始说起,直接上代码
ObjectAnimator.ofFloat(view,"rotationX",360)
.setDuration(1000)
.start();
以上代码的效果,如下:
对于ObjectAnimator
1、提供了ofInt、ofFloat、ofObject,这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值。
当对于属性值,只设置一个的时候,会认为以对象该属性的值为开始(getPropName反射获取),然后设置的值为终点。如果设置两个,则一个为开始、一个为结束~~~
动画更新的过程中,会不断调用setPropName更新元素的属性,所有使用ObjectAnimator更新某个属性,必须得有getter(设置一个属性值的时候)和setter方法~
如果你操作对象的该属性方法里面,比如上例的setRotationX如果内部没有调用view的重绘,则你需要自己按照下面方式手动调用。
anim.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
// view.postInvalidate();
// view.invalidate();
}
});
上面的例子只对view的单一属性做了改变,那么如果我希望一个动画能够让View既可以缩小、又能够淡出(3个属性scaleX,scaleY,alpha)呢?通常这样的需求我们会使用AnimationSet动画组合的方式去实现,那么,如果我只想使用ObjectAnimation去实现呢?
你需要这样写:
ObjectAnimator anim = ObjectAnimator
.ofFloat(view, "abc", 1.0F, 0F)//这里的属性随便写一个view没有的属性
.setDuration(1000);
anim.start();
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
/**
* 注意在这里设置的属性,他们的值变化都和上面填的值相关,
* 如果想在这里让view3d旋转,当然也是可以的,但是1f到0f的转动角度太小,难以观测
* 所以需要同时修改那几个属性,需要自己做取舍
* */
float cVal = (Float) animation.getAnimatedValue();
view.setAlpha(cVal);
view.setScaleX(cVal);
view.setScaleY(cVal);
}
});
效果如下
同样能实现上面效果的还有另外一种方式,使用propertyValuesHolder
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f,
0f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f,
0);
PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f,
0);
ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY,pvhZ).setDuration(1000).start();
ValueAnimator:属性动画中的时间驱动,管理着动画时间的开始、结束属性值,相应时间属性值计算方法等。包含所有计算动画值的核心函数以及每一个动画时间节点上的信息、一个动画是否重复、是否监听更新事件等,并且还可以设置自定义的计算类型。
特别注意:ValueAnimator只是动画计算管理驱动,设置了作用目标,但没有设置属性,需要通过updateListener里设置属性才会生效。
下面的代码与第一个ObjectAnimation的3D翻转效果是一样的
ValueAnimator valueAnimator=ValueAnimator.ofFloat(0,360);
valueAnimator.setTarget(view);
valueAnimator.setDuration(1000).start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
view.setRotationX((Float) animation.getAnimatedValue());
view.mXXX=(Float) animation.getAnimatedValue();//只要能访问到属性,不需要geter和seter也可以改变它
}
});
大眼看上去可以发现和ObjectAnimator没啥区别,实际上正是由于ValueAnimator不直接操作属性值,所以要操作对象的属性可以不需要setXXX与getXXX方法,你完全可以通过当前动画的计算去修改任何属性。
AnimationSet:动画集合,提供把多个动画组合成一个组合的机制,并可设置动画的时序关系,如同时播放、顺序播放或延迟播放。具体使用方法比较简单,如下:
ObjectAnimator a1 = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0f);
ObjectAnimator a2 = ObjectAnimator.ofFloat(view, "translationY", 0f, viewWidth);
......
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(5000);
animSet.setInterpolator(new LinearInterpolator());
//animSet.playTogether(a1, a2, ...); //两个动画同时执行
animSet.play(a1).after(a2); //先后执行
......//其他组合方式
animSet.start();
Evaluators相关类解释: Evaluators就是属性动画系统如何去计算一个属性值。它们通过Animator提供的动画的起始和结束值去计算一个动画的属性值。
-
IntEvaluator:整数属性值。
-
FloatEvaluator:浮点数属性值。
-
ArgbEvaluator:十六进制color属性值。
-
TypeEvaluator:用户自定义属性值接口,譬如对象属性值类型不是int、float、color类型,你必须实现这个接口去定义自己的数据类型。
既然说到这了,那就来个例子吧,譬如我们需要实现一个自定义属性类型和计算规则的属性动画,如下类型float[]:
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(5000);
valueAnimator.setObjectValues(new float[2]); //设置属性值类型
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator<float[]>()
{
@Override
public float[] evaluate(float fraction, float[] startValue,
float[] endValue)
{
//实现自定义规则计算的float[]类型的属性值
float[] temp = new float[2];
temp[0] = fraction * 2;
temp[1] = (float)Math.random() * 10 * fraction;
return temp;
}
});
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
float[] xyPos = (float[]) animation.getAnimatedValue();
view.setHeight(xyPos[0]); //通过属性值设置View属性动画
view.setWidth(xyPos[1]); //通过属性值设置View属性动画
}
});
推荐阅读
-
在电脑上安装配置使用安卓Android模拟器的方法(图文教程)
-
PanFone Mobile Data Transfe如何使用?安卓iPhone互传工具使用教程
-
忘了诺基亚 双屏安卓机才是微软的归宿
-
弃iOS不用 iPhone手机刷入安卓系统:黑客大神总是不一般
-
iPhone 7能刷安卓10.0?掌控该技术的公司被苹果起诉
-
苹果iOS千元机会干掉整个安卓?还真不一定拼过中国品牌
-
谷歌为安卓开发增量文件系统:游戏无需下载完就能上手玩
-
10年安卓党告诉你 iPhone 11为何值得果粉骄傲
-
曾经用户数过亿的手机操作系统们 是怎么输给苹果跟安卓的?
-
微软全新系统Windows Lite曝光:兼容安卓APP 快速流畅