属性动画(Property Animation)

属性动画的特性

1.Duration(持续时间)
2.时间插着器(Time interpolation):指定这个属性的值变化的方式。比如,变化越来越快,或是越来越慢。
3.重复的次数和方式(Repeat count and behavior):你可以指定动画是否重复播放、重复的次数、重复的方式(从头到尾正向重复还是从尾到头反向重复)
4.动画集合(Animator sets):将多个动画组织成一个逻辑集合,你可以让这些动画同时播放,或是一个一个顺序播放,或是其他逻辑。
5.帧刷新频率(Frame refresh delay):即,属性的值得刷新频率。系统默认10ms,不过实际刷新频率,还是又系统的繁忙程度和系统时钟的快慢来决定的。

时间插值器(TimeInterpolator)

一句话总结时间插值器的作用:根据当前的时间进度比,计算出当前动画进度比例。

TimeInterpolator本身是一个接口,它的实现类决定了动画变化的速度。你如果不想让你的动画是线性匀速变化,比如加速或减速变化,就需要实现这个方法。

//接口代码
public interface TimeInterpolator { 
    float getInterpolation(float input);
}

getInterpolation()方法的参数:input = 过去的时间 / 总时间。表示动画的当前时间位置,0表示开始,1.0表示结束。
getInterpolation()的返回值则表示经过插值计算之后的值,一般在0-1之间,不过,这个返回值可能存在小于0和大于1的情况,这是为了实现越界反弹等动画效果。

线性插值器LinearInterpolator的getInterpolation()只是简单的将input返回,方法体如下

public float getInterpolation(float input) {
    return input;
}

加速插值器AccelerateInterpolator的getInterpolation()默认情况下回返回input的平方。

public float getInterpolation(float input) {
    if (mFactor == 1.0f) {
        return input * input;
    } else {
        return (float)Math.pow(input, mDoubleFactor);
    }
}

类型求值器(TypeEvaluator)

TypeEvaluator根据当前时间点的动画进度,计算出属性当前时间点的值。

在上面我们知道TimeInterpolator根据当前的时间进度比,计算出动画进度应有的比例。那么TypeEvaluator就是根据这个动画进度参数、属性初始值,属性最终值,就算出当前时间下的属性的值。

//TypeEvaluator接口代码
public interface TypeEvaluator<T> {
    //根据动画进度,属性起始值和结束值,计算出当前值
    public T evaluate(float fraction, T startValue, T endValue);
}

TypeEvaluator是用来计算属性值,它的实现类有IntEvaluator, FloatEvaluator, ArgbEvaluator等,分别用于不同类型的属性。比如你的属性是int类型的,则对应IntEvaluator

//IntEvaluator的实现
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
    int startInt = startValue;
    return (int)(startInt + fraction * (endValue - startInt));
}

Property Animation 和 View Animation的区别

  1. View Animation 只能用于View及View的子类的对象;Property Animation则没有这样的限制
    2.View Animation限制较多,一些动画,只能用于没有background的view,否则会打不到预期效果;如,缩放一个view时,这是缩小了view的外观,她的background并没有改变,所以如果background不是透明的,则会露馅。
    3.View Animation只是简单的改变View的绘制,并不会改变View本身。比如,你将一个button从位置1移动到位置2,但是触发点击事件的位置还是在位置1。Property Animation这不会出现这种情况。
  2. View Animation 使用的代码较少,启动所花费的时间也短,如果View Animation能够达到你想要的效果,你同样可以继续使用它。你可以根据情况的不同,选择使用哪种动画。

ValueAnimator

举个栗子

ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.start();

上面这段代码中,ValueAnimator在1000ms内,在0f-1f之间,不断地改变这个浮点类型的值,0f是开始值,1f是结束值。

ValueAnimator有工厂方法ofInt()、ofFloat()、ofObject()用于不同的类型。

对于自定义类型,你可以这样:

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();

在这段代码中,ValueAnimator在开始值startPropertyValue和结束值endPropertyValue之间,不断的计算属性值。

上面的代码并没有真正作用到一个对象上,除了属性值的改变,你观察不到任何变化。如果你想达到当属性值变化的同时,让某个对象(外观、内容等任意)也随之改变,你需要为这个ValueAnimator设置Animation Listeners.当属性动画时间周期内发生重要事件,比如帧刷新,此Listener可以通过getAnimatedValue()得到这个属性在此时的值,然后根据这个值,去做相应的操作,比如移动控件的位置,改变大小等。

ObjectAnimator

ObjectAnimator是ValueAnimator的子类。其让属性动画作用于任何对象都变得很简单,而不再需要实现ValueAnimator.AnimatorUpdateListener,因为这个对象的属性会自动的刷新。

举个栗子

ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();

ObjectAnimator会不断的改变对象foo的透明度。
foo对象的类中必须有setAlpha(float alpha)成员函数

ObjectAnimator注意事项

1.动画作用于的目标对象的属性必须有set<propertyName>()形式的setter方法。ObjectAnimator通过这个方法更新此属性的值。
2.如果你没有为参数values...提供起始值,比如,ObjectAnimator.ofFloat(foo, "alpha")或ObjectAnimator.ofFloat(foo, "alpha",1f)(提供一个值,则作为结束值),你必须提供getter方法,形如get<propertyName>(),如getAlpha();
3.getter和setter方法的参数类型必须和ObjectAnimator.ofXXX(targetObject,"propName",values...)的values的类型相同。
4.根据用于动画的属性的不同,你可能需要调用view的invalidate()方法强制在重绘view。你可以在onAnimationUpdate()中调用invalidate();比如,Drawable的color属性,只有当此Drawable重绘时才会引起屏幕刷新。

Animation Listeners

你可以用下面的Listener监听动画,一边在重要事件发生是,有所操纵。

Animator.AnimatorListener
ValueAnimator.AnimatorUpdateListener
AnimatorListenerAdapter -- 用与代替Animator.AnimatorListener

如果你不想实现AnimatorListener的所有方法,你可以使用AnimatorListenerAdapter代替,AnimatorListenerAdapter使用空方法实现了AnimatorListener的所有方法。

举个栗子

ValueAnimatorAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
    public void onAnimationEnd(Animator animation) {
        balls.remove(((ObjectAnimator)animation).getTarget());
    }
}

布局动画

属性动画同样可以想应用于View那样方便的应用于ViewGroup。通过调用ViewGroup#setLayoutTransition(LayoutTransition)方法为其设置

你可以通过使用LayoutTransition的方法[setAnimator()](http://developer.android.com/reference/android/animation/LayoutTransition.html#setAnimator(int, android.animation.Animator)),并传入一个 Animator和一个下面的常量(定义在LayoutTransition中)值作为参数,来定制用于ViewGroup的动画。

  • APPEARING
    指明这个动画是用于当某个条目显示出来时使用.
  • CHANGE_APPEARING
    指明当有条目显现时,这个动画用于其他item.
  • DISAPPEARING
    指明这个动画是用于当某个条目隐藏时使用.
  • CHANGE_DISAPPEARING
    指明当有条目隐藏时,这个动画用于其他item.

你可以在ViewGroup的xml中添加android:animateLayoutchanges="true"来为ViewGroup指定默认动画。
栗子

<LinearLayout
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:id="@+id/verticalContainer"
    android:animateLayoutChanges="true" />

指定关键帧 Keyframes

一个Keyframe对象有一个time/value对组成,用于指定在特定时间点,动画的状态。每一个关键帧都可以有它自己的插值器,用来控制前一个关键帧和此关键帧的关系。

  1. 你必须使用方法ofInt(), ofFloat(), 和ofObject()中的一个来获得一个关键帧实例。
  2. 然后调用PropertyValuesHolder的工厂方法[ofKeyframe()](http://developer.android.com/reference/android/animation/PropertyValuesHolder.html#ofKeyframe(android.util.Property, android.animation.Keyframe...))来获得一个PropertyValuesHolder对象。
  3. 然后,将PropertyValuesHolder对象作为ObjectAnimator.ofPropertyValuesHolder()方法的参数,即可构造出一个对象。

栗子

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

推荐阅读更多精彩内容