Android Activity切换动画异常:API34下overrideActivityTransition未达预期
Activity切换动画适配问题及解决方案
需求与初始实现
要实现Activity切换动画:从Activity A启动Activity B时,A向左滑出屏幕,B从右侧滑入。初始采用版本兼容逻辑:
if (Build.VERSION.SDK_INT >= 34) { overrideActivityTransition( ComponentActivity.OVERRIDE_TRANSITION_OPEN, R.anim.slide_in_from_right, R.anim.slide_out_left ) } else overridePendingTransition( R.anim.slide_in_from_right, R.anim.slide_out_left )
具体代码实现
T1Activity(启动页)
class T1Activity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { AndroidMex4Theme { T1Screen() { startNextActivity() } } } } private fun startNextActivity() { startActivity(Intent(this@T1Activity, T2Activity::class.java)) if (Build.VERSION.SDK_INT < 34) overridePendingTransition( R.anim.slide_in_from_right, R.anim.slide_out_left, ) else overrideActivityTransition( OVERRIDE_TRANSITION_OPEN, R.anim.slide_in_from_right, R.anim.slide_out_left, ) } }
T2Activity(目标页)
class T2Activity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { if (Build.VERSION.SDK_INT >= 34) { overrideActivityTransition( OVERRIDE_TRANSITION_OPEN, R.anim.slide_in_from_right, R.anim.slide_out_left, ) } super.onCreate(savedInstanceState) setContent { AndroidMex4Theme { T2Screen { startNextActivity() } } } } }
动画文件定义
slide_in_from_right
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300"> <translate android:fromXDelta="100%" android:toXDelta="0%" /> </set>
slide_out_left
<set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300"> <translate android:fromXDelta="0" android:toXDelta="-100%" /> </set>
遇到的问题
- SDK<34时,
overridePendingTransition勉强生效,但Activity A会闪烁变白后消失 - SDK34时,
overrideActivityTransition效果不稳定,仅成功一次无法复现,且Activity B实际从左侧滑入而非右侧 - 需要添加
FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TASK清除返回栈,增加实现复杂度 - 不理解
overrideActivityTransition中OVERRIDE_TRANSITION_OPEN/CLOSE的作用,不清楚如何实现返回时的反向动画
解决方案
1. 修复SDK<34时的闪白问题
闪白源于Activity启动时的默认背景,给目标Activity添加透明主题:
在styles.xml中定义:
<style name="TransparentActivityTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowIsTranslucent">true</item> </style>
在Manifest中为Activity绑定该主题:
<activity android:name=".T1Activity" android:theme="@style/TransparentActivityTheme"/> <activity android:name=".T2Activity" android:theme="@style/TransparentActivityTheme"/>
2. 正确使用SDK34+的overrideActivityTransition
OVERRIDE_TRANSITION_OPEN:用于启动新Activity时的进入/退出动画OVERRIDE_TRANSITION_CLOSE:用于当前Activity被finish(如返回操作)时的进入/退出动画- 注意:该方法需在
startActivity或finish之前调用,而非之后
修改T1Activity的启动逻辑:
private fun startNextActivity() { if (Build.VERSION.SDK_INT >= 34) { overrideActivityTransition( OVERRIDE_TRANSITION_OPEN, R.anim.slide_in_from_right, R.anim.slide_out_left ) } startActivity(Intent(this@T1Activity, T2Activity::class.java)) if (Build.VERSION.SDK_INT < 34) { overridePendingTransition( R.anim.slide_in_from_right, R.anim.slide_out_left ) } }
3. 处理返回栈清除时的动画
使用FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TASK时,需在启动前设置过渡:
private fun startNextActivityWithClearStack() { val intent = Intent(this@T1Activity, T2Activity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } if (Build.VERSION.SDK_INT >= 34) { overrideActivityTransition( OVERRIDE_TRANSITION_OPEN, R.anim.slide_in_from_right, R.anim.slide_out_left ) } startActivity(intent) if (Build.VERSION.SDK_INT < 34) { overridePendingTransition( R.anim.slide_in_from_right, R.anim.slide_out_left ) } }
4. 实现返回时的反向动画
首先定义反向动画文件:
slide_in_from_left.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300"> <translate android:fromXDelta="-100%" android:toXDelta="0%" /> </set>
slide_out_right.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300"> <translate android:fromXDelta="0%" android:toXDelta="100%" /> </set>
然后在Activity中处理返回逻辑:
override fun onBackPressed() { if (Build.VERSION.SDK_INT >= 34) { overrideActivityTransition( OVERRIDE_TRANSITION_CLOSE, R.anim.slide_in_from_left, R.anim.slide_out_right ) } super.onBackPressed() if (Build.VERSION.SDK_INT < 34) { overridePendingTransition( R.anim.slide_in_from_left, R.anim.slide_out_right ) } }
或使用Jetpack的OnBackPressedDispatcher:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ...其他初始化代码 onBackPressedDispatcher.addCallback(this) { if (Build.VERSION.SDK_INT >= 34) { overrideActivityTransition( OVERRIDE_TRANSITION_CLOSE, R.anim.slide_in_from_left, R.anim.slide_out_right ) } finish() if (Build.VERSION.SDK_INT < 34) { overridePendingTransition( R.anim.slide_in_from_left, R.anim.slide_out_right ) } } }
内容的提问来源于stack exchange,提问作者shadox
相关产品推荐
相关产品推荐

