Android 动画 | 艺术探索笔记

Android 动画分为两大类

  • 视图动画
  • 属性动画

视图动画(View animation)

视图动画分为

  • 补间动画
  • 帧动画

补间动画(Tween animation)

补间动画有四类

名称 XML 标签 子类 效果
平移动画 <translate> TranslateAnimation 移动 View
缩放动画 <scale> ScaleAnimation 缩放 View
旋转动画 <rotate> RotateAnimation 旋转 View
透明度动画 <alpha> AlphaAnimation 改变 View 透明度

在 XML 中使用补间动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>

<set>标签表示动画集合,在它内部可以包含多个补间动画,它存在两个属性

  • android:interpolator
  • android:shareInterpolator

android:interpolator表示该动画集合的插值器。Android 中内置了九种插值器供我们选择,默认为accelerate_decelerate_interpolator,即先加速后减速。

内置的九种插值器

android:shareInterpolator表示集合中的动画和集合是否共用一个插值器。

<alpha>标签表示透明度动画,它的属性有

  • android:fromAlpha:透明度的起始值
  • android:toAlpha:透明度的结束值

<scale>标签表示缩放动画,它的属性有

  • android:fromXScale:水平方向缩放的起始值
  • android:toXScale:水平方向缩放的结束值
  • android:fromYScale:竖直方向缩放的起始值
  • android:toYScale:竖直方向缩放的结束值
  • android:pivotX:缩放轴点的 x 坐标
  • android:pivotY:缩放轴点的 y 坐标

默认情况下,轴点为 View 的中心点。轴点为中心点意味着,会从左右两边同时缩放。如果轴点为右边界,那么 View 就只会从左边缩放。

<translate>标签表示平移动画,它的属性有

  • android:fromXDelta:x 的起始值
  • android:toXDelta:x 的结束值
  • android:fromYDelta:y 的起始值
  • android:toYDelta:y 的结束值

<rotate>标签表示旋转动画,它的属性有

  • android:fromDegrees:旋转开始角度
  • android:toDegrees:旋转结束角度
  • android:pivotX:旋转轴点的 x 坐标
  • android:pivotY:旋转轴点的 y 坐标

轴点即为旋转轴,默认情况为 View 的中心点。

除此之外,补间动画还有一些通用的属性

  • android:duration:动画持续时间
  • android:fillAfter:动画结束后是否停留在结束位置,true 为停留,false 不停留

定义一个动画

// res/anim/animation.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:zAdjustment-"normal" >

    <rotate
        android:duration="100"
        android:fromDegrees="0"
        android:toDegrees="90" />
</set>

使用该动画

Button b = (Button) findViewById(R.id.button);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation);
b.startAnimation(animation);

帧动画(Frame animation)

帧动画的使用

// res/drawable/frame_animation.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/image1" android:duration="1000" />
    <item android:drawable="@drawable/image1" android:duration="1000" />
    <item android:drawable="@drawable/image1" android:duration="1000" />
</animation-list>

android:oneshot表示是否只播放一次,默认为 false。

使用帧动画

Button b = (Button) findViewById(R.id.button);
b.setBackgroundResource(R.drawable.frame_animation);
AnimationDrawable d = (AnimationDrawable) b.getBackground();
d.start();

帧动画时应避免使用多张大图,否则容易引起内存溢出。

属性动画(Property animation)

属性动画于 Android 3.0(API 11)引入。与视图动画(View animation)不同的是,属性动画可以对任意象做动画,也包括没有对象的情况。与视图动画不同的是,属性动画会真正的改变对象的属性。

属性动画的工作流程

  1. 设置动画运行时长、动画效果以及初始值和结束值
  2. 通过插值器和估值器设置属性的变化逻辑
  3. 根据步骤二的变化逻辑不断改变值
  4. 根据值的改变给对象赋值
  5. 调用 invalidate 方法绘制视图
  6. 重复步骤四和步骤五,直到初始值等于结束值
属性动画工作流程

属性动画常用类

  • ObjectAnimator
  • AnimatorSet
  • ValueAnimator

ValueAnimator

ValueAnimator 获取变化后的值,手动将值赋给对象的属性,从而实现动画效果。

ValueAnimator 流程

ValueAnimator.ofInt、ValueAnimator.ofFloat、ValueAnimator.ofObject 方法分别会以整型、浮点型、对象的方式将初始值过度到结束值。在这三个方法中需要传入动画的初始值、中间值(可以不传入)和结束值,在使用 ValueAnimator 时需要添加监听,以便得到执行过程中每一个动画值。

通过 Java 代码实现动画

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 5);
valueAnimator.setDuration(1000);
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        // 获得变化后的属性值
        float currentValue = (float) animation.getAnimatedValue();
        Log.d("ValueAnimator", "动画值:" + currentValue);
        // 手动设置属性值
        button.getLayoutParams().width = currentValue;
        // 刷新视图
        button.requestLayout();
    }
});

ObjectAnimator

ObjectAnimator 获取变化后的值,通过 get 和 set 方法自动将值赋给对象的属性,从而实现动画效果。

ObjectAnimator 流程

ObjectAnimator 继承自 ValueObject,所以同样有 ObjectAnimator.ofInt、ObjectAnimator.ofFloat、ObjectAnimation.ofObject 方法,作用与 ValueAnimator 类似。

通过 Java 代码实现动画

ObjectAnimator.ofFloat(button, "translationX", 0, 100).setDuration(1000).start();

AnimatorSet

通过 Java 代码实现动画

AnimationSet set = new Animation();
set.playTogether(
    ObjectAnimator.ofFloat(imag, "translationX", 0, 100),
    ObjectAnimator.ofFloat(imag, "translationY", 0, 100),
    ObjectAnimator.ofFloat(imag, "rotationX", 0, 360)
);
set.setDuration(3000).start();

通过 XML 定义动画

// res/animator/property_animator.xml
<set
  android:ordering=["together" | "sequentially"]>

    <objectAnimator
        android:propertyName="string"
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]/>

    <animator
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]/>
</set>

<set><objectAnimator><animator>分别对应 AnimatorSet、ObjectAnimator 和 ValueAnimator。

android:ordering中选择together表示子动画同时播放,选择sequentially表示子动画按前后顺序播放。默认值为together

<animator>的属性与<objectAnimator>类似,只是没有android:propertyName属性,这里只列出<objectAnimator>属性

  • android:propertyName:属性动画的作用对象和属性名称
  • android:duration:动画持续时间
  • android:valueFrom:属性起始值
  • android:valueTo:属性结束值
  • android:startOffset:动画延迟播放时间
  • android:repeatCount:动画重复次数
  • android:repeatMode:动画重复模式
  • android:valueType:表示android:propertyName所指定的属性类型

android:repeatCount的默认值为 0,为 -1 时表示无限循环。若android:propertyName指定属性表示的是颜色,则android:valueType不需要指定。

使用该 XML

AnimationSet set = (AnimatorSet) AnimatorInflater.loadAnimation(
    mContext, R.anim.property_animator);
set.setTarget(button);
set.start();

插值器(Interpolator)与估值器(TypeEvaluator)

Interpolator 被译为插值器,它的作用是根据时间流逝的百分比来计算当前属性值需要改变的百分比。在补间动画的介绍中,可以看到系统一共内置了九种插值器。

TypeEvaluator 译为类型估值算法或者估值器,它的作用是根据当前百分比来计算改变后的属性值。系统内置有 IntEvaluator、FloatEvaluator 和 ArgbEvaluator(针对 Color 属性)。

来看 IntEvaluator 的代码

public class IntEvaluator implements TypeEvaluator<Integer> {
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int) (startInt + fraction * (endValue - startInt));
    }
}

可以看到,IntEvaluator 会根据传入的估值 fraction 来计算当前需要变化的值。

当想要自定义插值器时,需要实现 Interpolator 或 TimeInterpolator。自定义估值器需要实现 TypeEvaluator。

文中流程图都来自 Carson_Ho 博客

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

推荐阅读更多精彩内容

  • 【Android 动画】 动画分类补间动画(Tween动画)帧动画(Frame 动画)属性动画(Property ...
    Rtia阅读 6,164评论 1 38
  • 1 背景 不能只分析源码呀,分析的同时也要整理归纳基础知识,刚好有人微博私信让全面说说Android的动画,所以今...
    未聞椛洺阅读 2,711评论 0 10
  • 一: 传统 View 动画(Tween/Frame) 1.1 Tween 动画 主要有 4 中:缩放、平移、渐变、...
    dfg_fly阅读 721评论 1 2
  • Animation Animation类是所有动画(scale、alpha、translate、rotate)的基...
    四月一号阅读 1,921评论 0 10
  • 初中文言文占教材课文的30%以上,高中文言文占教材课文的50%以上。所有文言诗文都是在特定历史环境下创作的,只有学...
    青岛远方文学阅读 329评论 0 0