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



    

activity_open_exit.xml 对应startActivity时的exitAnim



    

activity_close_enter 对应finish时的enterAnim



    

activity_close_exit 对应finish时的exitAnim



    
    

我们在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

    

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

    

在Manifest中将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栈的过场动画就也保持一致啦。

    

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... sharedElements) 

跳转使用下面的方法

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

回退时注意需要使用

   finishAfterTransition()

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

总结

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

参考

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

你可能感兴趣的:(Activity过场动画干货总结)