爱她就要了解她之Android动画

在Android中的动画主要有四种形式
1.Tween Aniamtion(变换动画)
2.Property Animation(属性动画)
3.Layout Animation(布局动画)
4.Frame Animation(逐帧动画)
在我们的应用中适当地使用动画,可以让我们的应用更加美观、柔和,对用户来说也会更加友好。

Tween Aniamtion

Tween Animation分为四种:
Alpha:渐变透明度动画
Scale:渐变尺寸缩放动画
Translate:位置移动变换动画
Rotate:旋转动画
共同属性:
(1)duration:动画持续时间。单位:毫秒
(2)reaptCount:动画重复次数
(3)reaptMode:动画重复模式(值:倒序重复 REVERSE,顺序重复 RESTART)
(4)startOffset:动画之间的时间间隔
(5)fillAfter:设置为true,表示动画转化效果在动画结束后被应用
(6)fillBefore:设置为true,表示动画转化效果在动画开始前被应用
(7)interprolator:动画插入器(加速、减速插入器)
以上的共同属性都可以通过set方式进行设置。
下面对这四种动画类型一一介绍
我们首先初始化一个View,以便下面演示

ImageView img = new ImageView(this)

1.Alpha

对view的透明度进行设置的取值范围是0.0~1.0
0.0表示完全透明 1.0表示完全不透明
Java Code:

AlphaAnimation alpha = new AlphaAnimation(0F,1F);

该构造方法中的第一个参数是初始透明度,第二个参数是最终透明度。

alpha.setDuration(1000)//设置持续时间

最后使用Vew的startAnimation()方法开始执行动画

img.startAnimation(alpha)//开始执行动画

XML配置文件
在xml中编写动画代码,需要在工程中的res目录下添加anim目录,然后在该目录中新建一个xml文件,然后如下编写:

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="0"
    android:toAlpha="1"
    android:duration="1000">
</alpha>

然后在Java Code中使用AnimationUtils类的loadAnimation(Context context, int id)将xml中的动画文件加载进来。同样对于View使用startAnimation()方法即可

2.Scale

对View缩放的取值范围是从0~
0表示消失 1表示不缩放 >1表示放大
Java Code
ScaleAnimation有三个构造方法:

public ScaleAnimation(float fromX, float toX, float fromY, float toY)//前两个参数是ViewX方向的缩放,后两个参数是ViewY方向的缩放
public ScaleAnimation(float fromX, float toX, float fromY, float toY,float pivotX, float pivotY)//前四个参数和第一个构造方法一样,最后两个参数是缩放的中心点
public ScaleAnimation(float fromX, float toX, float fromY, float toY,int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)

对于第三个构造方法中前四个参数和第一个构造方法一样,后面四个参数:pivotXType与pivotYType指缩放中心点的类型,其值在Animation类中有定义:

RELATIVE_TO_SELF//指相对自身设置缩放中心
RELATIVE_TO_PARENT//指相对于view的父View设置缩放中心
ABSOLUTE//绝对的

最后的两个参数需使用百分比的方式设置缩放中心,即值为0~1F。
XML配置文件

<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXScale="0"
    android:toXScale="1"
    android:fromYScale="0"
    android:toYScale="1"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="1000">
</scale>

使用XML文件配置动画时,pivotX与pivotY既可以使用百分比方式,也可以使用dp方式

3.Translate

Java Code
Translate有两个构造方法:

public TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)//很容易理解,即X方向的移动距离,Y方向的移动距离
public TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue, 
                          int fromYType, float fromYValue, int toYType, float toYValue)

第二个构造方法中的fromXType与fromYType与ScaleAnimation中的pivotXType的值是一样的,默认为相对自身的当前位置,其他参数与第一个构造方法的参数含义一样
XML配置文件

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0"
    android:toXDelta="100"
    android:fromYDelta="0"
    android:toYDelta="100"
    android:duration="1000">
</translate>

比较简单,就不做详细介绍了。

4.Rotate

Java Code
RotateAnimation也有三个常用的构造方法:

public RotateAnimation(float fromDegrees, float toDegrees)//初始(from)的角度,结束时(to)的角度
public RotateAnimation(float fromDegrees, float toDegrees, float pivotX, float pivotY)
public RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue,int pivotYType, float pivotYValue)

后面两个构造方法的参数其实和上面介绍的Scale是一样,就不做介绍了
XML配置文件

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="360">
</rotate>

5.Animation中的interprolator

Animation中的interprolator最底层的接口是

public interface TimeInterpolator 

他的子类有:
AccelerateInterpolator 加速插值器(动画速率开始很慢,然后逐渐加速)
DecelerateInterpolator 减速插值器(动画速率开始很快,然后逐渐减速)
AccelerateDecelerateInterpolator 加速减速插值器(动画速率开始慢然后块)
LinearInterpolator 线性插值器(最简单的插值器,即使动画匀速运动)
BounceInterpolator 弹跳插值器(在动画结束时使View呈弹跳状态)
AnticipateInterpolator 回荡秋千插值器(开始向后荡,然后向前荡的插值器)
CycleInterpolator 正弦周期变化插值器(动画循环播放特定的次数,速率改变沿着正弦曲线)
OvershootInterpolator 向前甩一定值后再回到原来位置
AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值

Property Animation

属性动画实在API3.0之后出现的。属性动画相对于Tween传统动画具有一定的优越性,因为传统动画是不断调用onDraw()方法去重绘界面来实现动画效果,这在一定程度上必定会加大CPU负担,从而带来性能问题,并且传统动画只是重绘了界面,改变了View的显示位置,但是对用户的onClick等响应事件并没有发生相应的变化,所以传统动画并不适于那些具有交互的动画效果。而属性动画是改变View的属性值,真真正正改变了一个View,因此属性动画大大改变了传统动画的局限性。

ObjectAnimator

ObjectAnimator是属性动画中比较简单基础的类,我们可以使用以下方法为一个View添加动画效果。

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)

第一个参数即要添加动画效果的View
第二个参数时属性名称。其实只要一个View的API中为某个属性设置setter/getter方法,我们就可以为它添加属性动画,这个属性名称可以为"rotation"、"translateX"、"translateY"、"X"、"Y"等View属性。
第三个参数是一个可变参数,即我们需要设置的动画值。例如:

ObjectAnimator.ofFloat(img, "translateX", 0F, 100F);//X方向的偏移
ObjectAnimator.ofFloat(img, "translateY", 0F, 100F);//Y方向的偏移

多重动画的添加,我们可以使用如下方式
方式一:

ObjectAnimator.ofFloat(img, "translateX", 0F, 100F).setDuration(1000).start();
ObjectAnimator.ofFloat(img, "translateY", 0F, 100F).setDuration(1000).start();

这种方式并不是先执行“translateX”动画,再执行“translateY”动画,而是同时执行
方式二:

PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("rotation",0F,360F);
PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("translateX",0F,100F);
ObjectAnimator.ofPropertyValuesHolder(img,p1,p2).setDuration(1000).start();

方式三:

Animator anim1 = ObjectAnimator.ofFloat(img, "translateX", 0F, 100F);
Animator anim2 = ObjectAnimator.ofFloat(img, "translateY", 0F, 100F);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.playTogether(anim1,anim2);
set.start();

在AnimatorSet类中,有很多方法方便我们控制动画的执行流程

public void playSequentially(Animator... items)//顺序执行items
public Builder with(Animator anim)//与某个动画同时执行
public Builder before(Animator anim)//在某个动画执行之前执行anim
public Builder after(Animator anim)//在某个动画执行后执行anim

动画监听事件AnimatorListener

ObjectAnimator anim = ObjectAnimator.ofFloat(root, "translateX", 0F, 100F);
anim.addListener(new Animator.AnimatorListener(){
    @Override
    public void onAnimationStart(Animator animation){}//动画开始时执行
    @Override
    public void onAnimationEnd(Animator animation){}//动画结束后执行
    @Override
    public void onAnimationCancel(Animator animation){}//动画被取消掉时执行
    @Override
    public void onAnimationRepeat(Animator animation){}//动画重复时执行
});

当然有时候我们并不需要监听动画的这么多事件,那么我们可以使用AnimatorListenerAdapter这个抽象类,去重写我们需要监听的事件即可。

anim1.addListener(new AnimatorListenerAdapter(){
    @Override
    public void onAnimationEnd(Animator animation){
        super.onAnimationEnd(animation);    
    }
});

Layout Animation

所谓布局动画即添加到布局的动画效果,并且动画效果会影响到布局的子对象。
为布局添加动画需要使用到LayoutAnimationController这个类,该类有两个常用构造方法

public LayoutAnimationController(Animation animation)
public LayoutAnimationController(Animation animation, float delay)

这两个构造比较容易理解,往构造方法中传递一个Animation参数即可。第二个构造方法中的delay(延迟)指子对象出现的先后延迟时间,即第一个View子对象开始出现后delay秒,第二个View子对象出现。
新建好LayoutAnimationController对象之后,使用

view.setLayoutAnimation(LayoutAnimationController controller)

这样我们就为布局添加好了动画效果。
LayoutAnimationController中有这样一个方法setOrder(int order),该方法指定布局中子View出现的先后顺序,API为我们制定了三个值,在LayoutAnimationController类中

ORDER_NORMAL//顺序
ORDER_REVERSE//倒序
ORDER_RANDOM//随机

为布局添加布局改变动画
在Layout的XML配置文件中使用

android:animateLayoutChanges=["true"|"false"]

这样就会为我们的布局添加一个系统默认的布局改变动画效果。
当然我们也可以自定义这个动画效果
使用view.setLayoutTransition(LayoutTransition transition)方法即为布局添加了一个默认的布局改变动画,如果想改变这个动画,需要使用到

public void setAnimator(int transitionType, Animator animator)

这个方法,第一个参数指布局改变的类型,在LayoutTransition 类中API为我们提供了5个值

CHANGE_APPEARING//由于主容器新增加了一个View,而导致原来的View位置发生改变时触发的动画
CHANGE_DISAPPEARING//由于主容器移除了一个View,而导致原来的View位置发生改变时触发的动画
APPEARING//View显示时的动画
DISAPPEARING//View消失时的动画
CHANGING//包含上面所有的情况

XML配置文件
我们也可以在XML文件中为布局设置布局动画
首先使用XML创建一个Tween Animation
然后使用XML通过以下语法创建一个布局动画

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@[package:]anim/anim_resource_name"
    android:delay="0.5">
</layoutAnimation>

根节点必须是layoutAnimation,android:animation指定义的Tween Animation
最后在layout布局中为布局使用android:layoutAnimation="@[package:]anim/anim_resource_name"
将我们编写的layoutAnimation文件的文件名传递进去即可。

Frame Animation

这种类型的动画,在官方文档中是这样介绍的:

Frame动画是一系列图片按照一定的顺序展示的过程,和放电影的机制很相似,我们称之为逐帧动画。Frame动画既可以在XML文件中定义,也可以完全编码实现。

XML配置文件
在XML中进行定义时,文件既可以放在anim目录中也可以放在drawable文件中。语法如下:

<animation-list xmlns: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>

animation-list作为根节点是必须的
android:oneshot若设值为true表示动画执行一次,若设值为false表示动画会重复执行。
每一个<item>元素表示一帧动画,android:drawable表示一帧所对应的图片,android:duration表示该帧所执行的时间。
Java Code
若以纯编码实现Frame动画需要用到AnimationDrawable类,该类是Drawable的子类。
在Java代码中我们可以使用setBackgroundResource()方法将我们XML中定义的Frame动画设置到ImageView上

image.setBackgroundResource(R.anim.frame);  
AnimationDrawable anim = (AnimationDrawable) image.getBackground();  
anim.start();

如果想要停止掉动画,只需调用anim.stop()方法即可。
还可以通过以下方式定义一个Frame动画

AnimationDrawable frame = new AnimationDrawable();
for(int i = 0; i< 4; i++){
    int id = getResources().getIdentifier("f"+i,"drawable",getPackageName());
    Drawable drawable = getResources().getDrawable(id);
    frame.addFrame(drawable,300);
}
frame.setOneShot(true);
img.setBackgroundDrawable(frame);
frame.start();

注意:对于AnimationDrawable不要在Activity的onCreate()方法中去掉用start()方法,因为此时窗口对象Window还没有初始化,AnimationDrawable不能被追加到Window中的视图对象中,所以并没有效果。解决办法可以是将animation的start放在一个按钮的点击事件或其他响应事件中,也可以在onWindowFocusChanged方法中开始执行动画,onWindowFocusChanged方法会在窗口初始化完成后被执行,在onCreate()方法之后执行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 1 背景 不能只分析源码呀,分析的同时也要整理归纳基础知识,刚好有人微博私信让全面说说Android的动画,所以今...
    未聞椛洺阅读 2,689评论 0 10
  • 转载一篇高质量博文,原地址请戳这里转载下来方便今后查看。1 背景不能只分析源码呀,分析的同时也要整理归纳基础知识,...
    Elder阅读 1,937评论 0 24
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,426评论 25 707
  • 听了别人的故事我还是挺羡慕我自己的 有些人并不是我们表面看上去那么光鲜亮丽 有些日子过的也并不是表面所看到的那样的...
    囡唛阅读 221评论 0 0
  • 记得小时候,会呆呆地望着天上的星星,还记得有一个似勺子似的形状的图形,大人说叫北斗七星。看天上的月亮,好像里面有一...
    同处当下阅读 143评论 2 0