Android动画之AnimatorSet联合动画用法

1 AnimatorSet概述

已经讲完了ObjectAnimator的关键用法,可以利用现有的函数实现一个动画改变多个属性,多个动画一起执行类似ofPropertyValuesHolder和ObjectAnimator的ofxx函数同时写入两个属性的函数,但这些都是在一个动画中,所有的动画设置都是共用的。有时也需要能够让多个动画相互配合的运行,AnimatorSet就可以实现这个功能(其实我们也可以为每个动画设置监听,然后执行下一个动画,但是操作比较繁琐),AnimatorSet可以实现复杂的组合动画,既可以同时对多个对象做动画并控制执行顺序,也可以控制单个对象的动画执行顺序。
Android Developer :https://developer.android.google.cn/reference/android/animation/AnimatorSet

AnimatorSet可以指定一组动画的执行顺序,让它们可以一起执行,顺序执行,延迟执行。

1.1 AnimatorSet的生成:

代码直接利用 AnimatorSet()
如果是XML定义AnimatorSet 利用 AnimatorInflater.loadAnimator()加载(使用较少)
AnimatorSet可以作用于ObjectAnimator和ValueAnimator,但通常ObjectAnimator用的比较多。

1.2 AnimatorSet和ObjectAnimator中重叠的函数,谁生效?

查看AnimatorSet的方法,发现了几个和Animator动画相同的设置属性的方法,那么这些方法和内部单个动画同时设置谁生效呢?
setDuration (long duration):设置每个内部子动画的时长,默认每个子动画使用自己默认的时长,如果AnimatorSet设置了时长,子动画将继承这个时长,而子动画自己设置的duration将失效。
下面会列举其他方法,和setDuration方法类似,都是如果没有设置就使用子动画自己的,如果AnimatorSet设置了就使用AnimatorSet设置的属性。
setInterpolator (TimeInterpolator interpolator),设置之后内部子动画的插值器都是这个
setTarget(Object target),设置之后所有内部子动画都作用于相同的target目标对象

特例:
setStartDelay(long startDelay)函数是个特例,它不会覆盖子动画开始延迟,只对AnimatorSet的开始时间起作用,所以它会延后AnimatorSet激活整体动画的开始时间。

比较简单就不用代码说明了

1.3 两种添加动画到AnimatorSet的方法

  • 一种是利用playTogether()或者playSequentially(),可以一次添加所有的动画到AnimatorSet中,
  • 一种是利用play(Animator)构建Builder对象,然后利用Builder提供的方法,一个一个的添加动画,并设置各个动画间执行顺序的依赖关系

1.4 AnimatorSet的其他函数

cancle()取消动画,会取消AnimatorSet中的所有子动画。
end() 结束动画,会结束AnimatorSet中的所有子动画。
getChildAnimations() 获取所有受AnimatorSet控制的动画
isStarted(),AnimationSet动画是否开始了,true开始
isRunning(),AnimationSet开始之后(isStarted = true),内部是否有子动画正在执行,有动画执行返回true
pause()暂停动画,
resume()恢复暂停的动画
play(Animator anim)获取Builder对象

2 playTogether和playSequentially

2.1 playTogether

多个动画同时执行,可以是对一个对象执行的多个动画,也可以是对多个对象的多个动画。
playTogether(Collection<Animator> items) //利用集合添加动画
playTogether(Animator... items) //利用可变参数添加动画

多个动画作用于一个对象

ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, "backgroundColor", Color.WHITE, Color.GREEN);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, "scaleX", 0.1f, 1.2f);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, "scaleY", 0.5f, 1.0f);
ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(mTextView, "translationY", 0, 250);

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4);
animatorSet.setDuration(3000);
animatorSet.start();

如果多个动画同时对一个属性进行操作,会发生错误吗?
不会发生错误,会正常执行,只不过会按照playTogether添加的最后一个动画覆盖前面操作相同属性的动画,也可能没有覆盖,但确实是最后一个添加的动画起了作用。

 ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, "backgroundColor", Color.WHITE, Color.GREEN);
 ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, "scaleX", 0.1f, 1.2f);
 ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, "scaleY", 0.5f, 1.0f);
 ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(mTextView, "translationY", 0, 250);
 ObjectAnimator objectAnimator5 = ObjectAnimator.ofFloat(mTextView, "translationY", 200, 450);
 ObjectAnimator objectAnimator6 = ObjectAnimator.ofFloat(mTextView, "translationY", 300, 600);

 AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4,objectAnimator5,objectAnimator6);
 animatorSet.setDuration(3000);
 animatorSet.start();

animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4,objectAnimator5,objectAnimator6);
最终会按照objectAnimator6的效果进行展示。


Set图片2

animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator6,objectAnimator5,objectAnimator4);
最终会按照objectAnimator4的效果进行展示。


多个动画作用于多个对象

ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, "backgroundColor", Color.WHITE, Color.GREEN);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, "scaleX", 0.1f, 1.2f);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, "scaleY", 0.5f, 1.0f);
ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(mTextView, "translationY", 0, 250);

ObjectAnimator objectAnimator7 = ObjectAnimator.ofArgb(mTextView2, "backgroundColor", Color.WHITE, Color.GREEN);
ObjectAnimator objectAnimator8 = ObjectAnimator.ofFloat(mTextView2, "scaleX", 0.1f, 1.2f);
ObjectAnimator objectAnimator9 = ObjectAnimator.ofFloat(mTextView2, "scaleY", 0.5f, 1.0f);
ObjectAnimator objectAnimator10 = ObjectAnimator.ofFloat(mTextView2, "translationY", 0, 250);

ObjectAnimator objectAnimator11 = ObjectAnimator.ofArgb(mTextView3, "backgroundColor", Color.WHITE, Color.GREEN);
ObjectAnimator objectAnimator12 = ObjectAnimator.ofFloat(mTextView3, "scaleX", 0.1f, 1.2f);
ObjectAnimator objectAnimator13 = ObjectAnimator.ofFloat(mTextView3, "scaleY", 0.5f, 1.0f);
ObjectAnimator objectAnimator14 = ObjectAnimator.ofFloat(mTextView3, "translationY", 0, 250);

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4
,objectAnimator7,objectAnimator8,objectAnimator9,objectAnimator10,objectAnimator11,objectAnimator12,objectAnimator13,objectAnimator14);
animatorSet.setDuration(3000);
animatorSet.start();

2.2 playSequentially

顺序播放动画:
playSequentially(List<Animator> items)
playSequentially(Animator... items)

对于playSequentially作用于单个和多个对象的区别和playTogether一样,所以这里只讲解playSequentially作用于多个对象。

上面的代码修改为playSequentially,并且把时间修改为1000,否则每个动画顺序执行3s会很耗时间。

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4
,objectAnimator7,objectAnimator8,objectAnimator9,objectAnimator10,objectAnimator11,objectAnimator12,objectAnimator13,objectAnimator14);
animatorSet.setDuration(1000);
animatorSet.start();

注意:

  • playTogether和playSequentially只负责激活控件动画,后续的动画还是由ObjectAnimator自己控制。
  • playSequentially是一个动画执行完后执行下一个动画,但如果前一个动画是无限循环,下一个动画永远不会执行。

如何实现动画的循环播放

AnimatorSet中没有设置动画执行次数的函数,所以无法利用AnimatorSet设置动画循环播放, playSequentially一个动画执行完后执行另外一个动画,如果前一个动画是无限循环,后一个动画不会执行,所以也无法实现循环播放动画,所以只能利用playTogether播放动画时每个动画设置无线循环:

ObjectAnimator objectAnimator5 = ObjectAnimator.ofFloat(mTextView, "translationY", 200, 450);
  ObjectAnimator objectAnimator6 = ObjectAnimator.ofFloat(mTextView, "translationY", 300, 600);
  ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, "backgroundColor", Color.WHITE, Color.GREEN);
  ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, "scaleX", 0.1f, 1.2f);
  ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, "scaleY", 0.5f, 1.0f);
  ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(mTextView, "translationY", 0, 250);

  ObjectAnimator objectAnimator7 = ObjectAnimator.ofArgb(mTextView2, "backgroundColor", Color.WHITE, Color.GREEN);
  ObjectAnimator objectAnimator8 = ObjectAnimator.ofFloat(mTextView2, "scaleX", 0.1f, 1.2f);
  ObjectAnimator objectAnimator9 = ObjectAnimator.ofFloat(mTextView2, "scaleY", 0.5f, 1.0f);
  ObjectAnimator objectAnimator10 = ObjectAnimator.ofFloat(mTextView2, "translationY", 0, 250);

  ObjectAnimator objectAnimator11 = ObjectAnimator.ofArgb(mTextView3, "backgroundColor", Color.WHITE, Color.GREEN);
  ObjectAnimator objectAnimator12 = ObjectAnimator.ofFloat(mTextView3, "scaleX", 0.1f, 1.2f);
  ObjectAnimator objectAnimator13 = ObjectAnimator.ofFloat(mTextView3, "scaleY", 0.5f, 1.0f);
  ObjectAnimator objectAnimator14 = ObjectAnimator.ofFloat(mTextView3, "translationY", 0, 250);
  objectAnimator1.setRepeatCount(-1);
  objectAnimator2.setRepeatCount(-1);
  objectAnimator3.setRepeatCount(-1);
  objectAnimator4.setRepeatCount(-1);
  objectAnimator5.setRepeatCount(-1);
  objectAnimator6.setRepeatCount(-1);
  objectAnimator7.setRepeatCount(-1);
  objectAnimator8.setRepeatCount(-1);
  objectAnimator9.setRepeatCount(-1);
  objectAnimator10.setRepeatCount(-1);
  objectAnimator11.setRepeatCount(-1);
  objectAnimator12.setRepeatCount(-1);
  objectAnimator13.setRepeatCount(-1);
  objectAnimator14.setRepeatCount(-1);

  AnimatorSet animatorSet = new AnimatorSet();
  animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4
  ,objectAnimator7,objectAnimator8,objectAnimator9,objectAnimator10,objectAnimator11,objectAnimator12,objectAnimator13,objectAnimator14);
//  animatorSet.play()
  animatorSet.setDuration(3000);
  animatorSet.start();

如果利用playSequentially并且前一个动画是循环动画:

所以最终实现循环动画的方法为,每个内部子动画设置为无限循环

3 利用play(Animator)构建Builder对象

Builder play(Animator anim);生成builder对象,Builder能够控制动画的执行顺序和相互之间的依赖。
通过AnimatorSet中的play方法可以获取AnimatorSet.Builder对象,通过Builder内部的函数添加动画到AnimatorSet中,后续的所有动画都是以play传入的动画为标准进行相应操作(后面会详细讲述)

Builder的函数:

public Builder with(Animator anim) 和前面动画一起执行
public Builder before(Animator anim) 执行前面的动画后再执行该动画
public Builder after(Animator anim) 先执行这个动画再执行前面动画
public Builder after(long delay) 延迟n毫秒之后执行动画

public Builder with(Animator anim) 和前面动画一起执行:

例子还用上面的动画,三个view同时执行变色动画:

ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, "backgroundColor", Color.WHITE, Color.GREEN);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, "scaleX", 0.1f, 1.2f);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, "scaleY", 0.5f, 1.0f);
ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(mTextView, "translationY", 0, 250);

ObjectAnimator objectAnimator7 = ObjectAnimator.ofArgb(mTextView2, "backgroundColor", Color.WHITE, Color.GREEN);
ObjectAnimator objectAnimator8 = ObjectAnimator.ofFloat(mTextView2, "scaleX", 0.1f, 1.2f);
ObjectAnimator objectAnimator9 = ObjectAnimator.ofFloat(mTextView2, "scaleY", 0.5f, 1.0f);
ObjectAnimator objectAnimator10 = ObjectAnimator.ofFloat(mTextView2, "translationY", 0, 250);

ObjectAnimator objectAnimator11 = ObjectAnimator.ofArgb(mTextView3, "backgroundColor", Color.WHITE, Color.GREEN);
ObjectAnimator objectAnimator12 = ObjectAnimator.ofFloat(mTextView3, "scaleX", 0.1f, 1.2f);
ObjectAnimator objectAnimator13 = ObjectAnimator.ofFloat(mTextView3, "scaleY", 0.5f, 1.0f);
ObjectAnimator objectAnimator14 = ObjectAnimator.ofFloat(mTextView3, "translationY", 0, 250);

AnimatorSet animatorSet = new AnimatorSet();
   animatorSet.play(objectAnimator1).with(objectAnimator7).with(objectAnimator11);
   animatorSet.setDuration(3000);
   animatorSet.start();

动画objectAnimator1作用于第一个view,objectAnimator7作用于第二个view,objectAnimator11作用于第三个view。

public Builder before(Animator anim) 执行前面的动画后再执行该动画:

第一个view先执行变色操作再执行X轴缩放操作:

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(objectAnimator1).before(objectAnimator2);
animatorSet.setDuration(3000);
animatorSet.start();

public Builder after(Animator anim) 先执行这个动画再执行前面动画:

第一个view先执行X轴缩放动画,再执行变色操作。

 AnimatorSet animatorSet = new AnimatorSet();
  animatorSet.play(objectAnimator1).after(objectAnimator2);
  animatorSet.setDuration(3000);
  animatorSet.start();

public Builder after(long delay) 延迟n毫秒之后执行动画

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(objectAnimator1).after(objectAnimator2).after(10000);
animatorSet.setDuration(3000);
animatorSet.start();

如果设置过after延迟执行之后设置setDuration,after延迟会被duration的时间覆盖,不会产生延迟,而且延迟是对play函数中的动画来说的,调用了after(非延迟)之后,after(非延迟)中的动画是不受after延迟时间影响的。

 animatorSet.play(objectAnimator1).after(objectAnimator2).after(10000);
// animatorSet.setDuration(3000);
 animatorSet.start();

4 AnimatorSet Builder的操作方式,每次play,或者链式操作

AnimatorSet 的play函数和Builder的with,before,after函数都返回Builder 对象实例,所以我们可每次通过play获取Builder进行动画操作,也可以利用Builder函数返回Builder对象的特性进行链式操作,两种操作方式有什么不同呢?

重要:
先看AnimatorSet的play方法产生的Builder对象:

* <p>Note that <code>play()</code> is the only way to tell the
* <code>Builder</code> the animation upon which the dependency is created,
* so successive calls to the various functions in <code>Builder</code>
* will all refer to the initial parameter supplied in <code>play()</code>
* as the dependency of the other animations. For example, calling
* <code>play(a1).before(a2).before(a3)</code> will play both <code>a2</code>
* and <code>a3</code> when a1 ends; it does not set up a dependency between
* <code>a2</code> and <code>a3</code>.</p>

public Builder play(Animator anim) {
    if (anim != null) {
        return new Builder(anim);
    }
    return null;
}

每次调用play方法都会产生一个新的Builder对象,这个对象约束内部动画的执行顺序。而且重要的一点是play()方法是唯一一种获取Builder对象的方式,后续所有的动画执行都以play方法中传入的动画为基准,例如:
AnimatorSet s = new AnimatorSet();
s.play(anim1).with(anim2);
s.play(anim2).before(anim3);
s.play(anim4).after(anim3);
动画anim1 和anim2有关系,anim2和anim3有关系,anim3和anim4有关系。anim1和anim2将同时执行,anim2先于anim3执行,anim3 先于anim4执行,所以最终的执行顺序为anim1和anim2同时开始执行,anim2执行完后开始执行anim3,anim3执行完后开始执行anim4.

代码示例:

animatorSet.play(objectAnimator1).before(objectAnimator2);
animatorSet.play(objectAnimator1).with(objectAnimator7);
animatorSet.play(objectAnimator7).after(objectAnimator11);
animatorSet.setDuration(3000);
animatorSet.start();

结果:动画会先执行objectAnimator11(gif中的第三个view变背景),然后objectAnimator1(gif中的第一个view变背景)和objectAnimator7(第二个view变背景)同时执行,最后执行objectAnimator2(缩放);


Builder with before after 函数返回Builder对象,链式操作动画

/**
 * Sets up the given animation to play at the same time as the animation supplied in the
 * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object.
 *
 * @param anim The animation that will play when the animation supplied to the
 * {@link AnimatorSet#play(Animator)} method starts.
 */
public Builder with(Animator anim) {
    Node node = getNodeForAnimation(anim);
    mCurrentNode.addSibling(node);
    return this;
}

/**
 * Sets up the given animation to play when the animation supplied in the
 * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
 * ends.
 *
 * @param anim The animation that will play when the animation supplied to the
 * {@link AnimatorSet#play(Animator)} method ends.
 */
public Builder before(Animator anim) {
    Node node = getNodeForAnimation(anim);
    mCurrentNode.addChild(node);
    return this;
}

/**
 * Sets up the given animation to play when the animation supplied in the
 * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
 * to start when the animation supplied in this method call ends.
 *
 * @param anim The animation whose end will cause the animation supplied to the
 * {@link AnimatorSet#play(Animator)} method to play.
 */
public Builder after(Animator anim) {
    Node node = getNodeForAnimation(anim);
    mCurrentNode.addParent(node);
    return this;
}

play之后的链式调用不会产生新的Builder对象,会把传入的动画添加到play函数产生的Builder对象的node列表中等待执行。
所以with before after 函数被调用之后链式操作动画是操作同一个Builder对象内部的Node链,所以都是以play函数传入的动画为基准。
play(a1).before(a2).before(a3) a2,a3动画都是以a1动画为基准,a1动画执行结束之后a2,a3将同时执行,a1动画和a2,a3有关系,但是a2,a3之间是没有关系的。

代码示例看下面:

5 Builder链式调用的一些举例

上面提到调用play函数后后续的所有动画都是以play传入的动画为标准进行相应操作
下面我们通过几个列子来说明:

AnimatorSet animatorSet = new AnimatorSet();
    animatorSet.play(objectAnimator1).before(objectAnimator2).before(objectAnimator3).before(objectAnimator4).with(objectAnimator7).with(objectAnimator11);
   animatorSet.setDuration(3000);
   animatorSet.start();

其中objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4 操作左边第一个view。
objectAnimator7操作第二个view,
objectAnimator11操作第三个view。

最终的结果为三个view同时开始动画也就是objectAnimator1,objectAnimator7,objectAnimator11同时开始执行,objectAnimator1执行完之后objectAnimator2,objectAnimator3,objectAnimator4同时开始执行。:


 AnimatorSet animatorSet = new AnimatorSet();
 animatorSet.play(objectAnimator1).before(objectAnimator2).before(objectAnimator3).before(objectAnimator4).with(objectAnimator7).with(objectAnimator11).after(objectAnimator12);
   animatorSet.setDuration(3000);
   animatorSet.start();

其中objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4 操作左边第一个view。
objectAnimator7操作第二个view,
objectAnimator11,objectAnimator12操作第三个view。
结果:objectAnimator12先执行动画,接着objectAnimator1,objectAnimator7,objectAnimator11动画会同时执行,objectAnimator1执行完之后objectAnimator2,objectAnimator3,objectAnimator4动画会同时执行。


animatorSet.play(objectAnimator1).before(objectAnimator2).after(objectAnimator4).before(objectAnimator3).after(objectAnimator14).after(objectAnimator11);
animatorSet.setDuration(3000);
animatorSet.start();

其中objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4 操作左边第一个view。
objectAnimator7操作第二个view,
objectAnimator11,objectAnimator12操作第三个view。
上面的代码会同时执行objectAnimator4,objectAnimator11,objectAnimator14,然后执行objectAnimator1,再执行objectAnimator2 和objectAnimator3


链式调用动画执行顺序总结如下:
Builder链式调用中会先执行after函数中的动画(有多个同时执行),然后执行play和with函数(有多个同时执行)中的动画,最后执行before函数中的动画(有多个同时执行)

6 AnimatorSet动画监听

//如果不想实现那么多方法,可以利用AnimatorListenerAdapter代替AnimatorListener
animatorSet.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) {

    }
});

//需要api19
animatorSet.addPauseListener(new Animator.AnimatorPauseListener() {
    @Override
    public void onAnimationPause(Animator animation) {
        
    }

    @Override
    public void onAnimationResume(Animator animation) {

    }
});

由于内部主要使用ObjectAnimator所以动画监听显得不那么重要。

7 AnimationSet xml 文件实现

用法不多,只举个例子(来自developer):

<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.animator.property_animator);
set.setTarget(myObject);
set.start();

Animation动画概述和执行原理
Android动画之补间动画TweenAnimation
Android动画之逐帧动画FrameAnimation
Android动画之插值器简介和系统默认插值器
Android动画之插值器Interpolator自定义
Android动画之视图动画的缺点和属性动画的引入
Android动画之ValueAnimator用法和自定义估值器
Android动画之ObjectAnimator实现补间动画和ObjectAnimator自定义属性
Android动画之ObjectAnimator中ofXX函数全解析-自定义Property,TypeConverter,TypeEvaluator
Android动画之AnimatorSet联合动画用法
Android动画之LayoutTransition布局动画
Android动画之共享元素动画
Android动画之ViewPropertyAnimator(专用于view的属性动画)
Android动画之Activity切换动画overridePendingTransition实现和Theme Xml方式实现
Android动画之ActivityOptionsCompat概述
Android动画之场景变换Transition动画的使用
Android动画之Transition和TransitionManager使用
Android动画之圆形揭露动画Circular Reveal
Android 动画之 LayoutAnimation 动画
Android动画之视图动画的缺点和属性动画的引入

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

推荐阅读更多精彩内容