Activity过场动画干货总结

大纲

大纲.png

Activity的overridePendingTransition方法

官方文档中说:

Call immediately after one of the flavors of startActivity(android.content.Intent) or finish() to specify an explicit transition animation to perform next.

文档指明overridePendingTransition必需在startActivity()或者finish()函数之后立即调用

public void overridePendingTransition (int enterAnim, int exitAnim)

overridePendingTransition()方法接收的是两个动画资源enterAnim和exitAnim。
当通过startActivity()从A进入B时,B执行enterAnim,A执行exitAnim;
当通过finish()从B回退A时,A执行enterAnim,B执行exitAnim。

我们这里模仿微信的推进推出效果,创建4个过场动画文件:
(这里注意一个点就是android:duration设置最好一致,因为如果在startActivity的时候进入enterAnim大于exitAnim,就会出现新的Activity还没有完全进入界面,而上一个页面已经滑出了导致背景全黑)
activity_open_enter.xml 对应startActivity时的enterAnim

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="100%"
        android:toXDelta="0"
        android:duration="300"/>
</set>

activity_open_exit.xml 对应startActivity时的exitAnim

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="300"
        android:fromXDelta="0"
        android:toXDelta="-100%" />
</set>

activity_close_enter 对应finish时的enterAnim

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate 
        android:duration="300"
        android:fromXDelta="-100%"
        android:toXDelta="0"/>
</set>

activity_close_exit 对应finish时的exitAnim

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="100%"
        android:duration="300">
    </translate>
</set>

我们在startActivity时

//MainActivity.kt
val intent = Intent(this@MainActivity, Step1Activity::class.java)
startActivity(intent)
overridePendingTransition( R.anim.activity_open_enter,  R.anim.activity_open_exit)

finish时

//Step1Activity.kt
finish()
overridePendingTransition( R.anim.activity_close_enter,  R.anim.activity_close_exit)

就实现了微信的推入推出的效果


仿微信Activity过场动画.gif

如果不需要切换动画可以设置overridePendingTransition(0,0),注意,不要动画不是默认动画,这里不要动画是直接显示新的Activity没有任何动画效果

另外官方文档后半部分中又引出了新的东西:

As of Build.VERSION_CODES.JELLY_BEAN an alternative to using this with starting activities is to supply the desired animation information through a ActivityOptions bundle to startActivity(android.content.Intent, android.os.Bundle) or a related function. This allows you to specify a custom animation even when starting an activity from outside the context of the current top activity.

在安卓5.0之后可以创建一个携带一个动画设置的ActivityOptions,在startActivity(android.content.Intent, android.os.Bundle)时转为Bundle使用。
文档给我们引出了一个新的东西——ActivityOptions,关于ActivityOptions的详细使用,它提供了多种动画的方法,这里暂时不多做扩展,只挑它两个使用方法先说,而且放在最后说,因为我们要先说安卓提供的另外一种过场动画的设置方法。

theme设置windowAnimationStyle

安卓提供了一组style属性可以直接在manifest里面设置某个Activity的过场动画,当然也可以直接设置在Application的theme上从而全局配置,这里的优先级是小于java代码中动态设置的。

activityOpenEnterAnimation
activityOpenExitAnimation
activityCloseEnterAnimation
activityCloseExitAnimation

这些属性对应与上面两种场景的两对参数,属性的名称也更加易懂
这里就以设置给Application为例创建一个WindowAnimationStyle

    <style name="WindowAnimationStyle" parent="@android:style/Animation.Activity">
        <item name="android:activityOpenEnterAnimation">@anim/activity_open_enter</item>
        <item name="android:activityOpenExitAnimation">@anim/activity_open_exit</item>
        <item name="android:activityCloseEnterAnimation">@anim/activity_close_enter</item>
        <item name="android:activityCloseExitAnimation">@anim/activity_close_exit</item>
    </style>

这里我们新建了一个全屏的AppTheme作为Application的theme,将这个windowAnimationStyle设置给AppTheme

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowAnimationStyle">@style/WindowAnimationStyle</item>
    </style>

在Manifest中将AppTheme设置给Application

 <application
        ......
        android:theme="@style/AppTheme">
    </application>

现在app中的所有页面基本都具有相同的转场动画了。为什么说基本上,因为这样设置后不同的Activity栈之间切换仍旧是默认的动画(如果这个时候跳转launchMode是singleTask或者使用Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK作为flag的,你会发现仍旧是默认的动画的,并且默认的跨任务栈的动画有些突兀)。谷歌提供了另外一组属性设置跨Activity栈的转场动画

taskOpenEnterAnimation
taskOpenExitAnimation
taskCloseEnterAnimation
taskCloseExitAnimation

我们把这几个属性在WindowAnimationStyle里面补齐,这样跨Activity栈的过场动画就也保持一致啦。

    <style name="WindowAnimationStyle" parent="@android:style/Animation.Activity">
        <item name="android:activityOpenEnterAnimation">@anim/activity_open_enter</item>
        <item name="android:activityOpenExitAnimation">@anim/activity_open_exit</item>
        <item name="android:activityCloseEnterAnimation">@anim/activity_close_enter</item>
        <item name="android:activityCloseExitAnimation">@anim/activity_close_exit</item>

        <item name="android:taskOpenEnterAnimation">@anim/activity_open_enter</item>
        <item name="android:taskOpenExitAnimation">@anim/activity_open_exit</item>
        <item name="android:taskCloseEnterAnimation">@anim/activity_close_enter</item>
        <item name="android:taskCloseExitAnimation">@anim/activity_close_exit</item>
    </style>

ActivityOptions

最后我们再来说下这个ActivityOptions。之所以放在最后说,是因为前两种比较相似,而ActivityOptions可以处理更复杂的效果,可以对过场的View等做操作,实现共享元素等更加炫酷的效果。
首先,这个ActivityOptions是完全可以替代overridePendingTransition,所以提供了一个类似的方法,接收两个动画资源

makeCustomAnimation(Context context,int enterResId, int exitResId) 

我们在MainActivity中这样启动Step1Activity

 val intent = Intent(this@MainActivity, Step1Activity::class.java)
 val activityOptions = ActivityOptions.makeCustomAnimation(this,  R.anim.activity_open_enter,  R.anim.activity_open_exit)
 startActivity(intent,activityOptions.toBundle())

这样就实现了跟上面一样的效果,但是我没有找到方法处理finish场景(在共享中倒是可以使用finishAfterTransition回退),如果你知道,欢迎在下方留言。

下面再说一下ActivityOptions实现共享元素,关于ActivityOptions其他的用法可以去查看官方文档

ActivityOptions共享元素

关于什么是共享元素,这个不太好解释,我们直接看例子吧

图-1 图-2
共享元素-1.gif
共享元素-2.gif

图-1的两个不同的Activity上显示logo的ImageView就是共享元素;图-2中的显示logo的View和另一个Activity上的back按钮也是共享元素,相信你已经明白什么叫共享元素了。
首先在跳转到的Step1Activity布局中为共享元素声明名称

      android:transitionName="transition"

MainActivity跳转用到了ActivityOptions的makeSceneTransitionAnimation方法,参数说明我已经标注在注释上了

    /**
     * @param sharedElement当前Activity中共享元素View
     * @param 跳转至页面共享元素名称
     */
makeSceneTransitionAnimation(Activity activity,View sharedElement, String sharedElementName)

当有多组共享元素时,还有另外一个方法

public static ActivityOptions makeSceneTransitionAnimation(Activity activity,Pair<View, String>... sharedElements) 

跳转使用下面的方法

val intent = Intent(this@MainActivity, Step1Activity::class.java)
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
                    this,
                    findViewById<ImageView>(R.id.iv_logo_top),
                    "transition"
                )
startActivity(intent, activityOptions.toBundle())

回退时注意需要使用

   finishAfterTransition()

才能在回退时也具有这个共享元素的动画

总结

一般我们可以通过theme的方法设置全局的Activity入场出厂动画,然后在一些需要特殊动画的地方使用ActivityOptions或overridePendingTransition处理特殊动画,因为代码中设置的动画的优先级要高,可以覆盖theme中设置的全局动画。

参考

Android动画之Activity切换动画overridePendingTransition实现和Theme Xml方式实现
Android页面切换动画(包括不同任务栈之间页面切换动画)通过Theme去设置

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

推荐阅读更多精彩内容