Android Compose Activity 页面跳转动画详解
下面我将全面详细地介绍在 Compose 中实现 Activity 跳转动画的各种方法,包括基础实现、高级技巧和最佳实践。
一、基础 Activity 过渡动画
1. overridePendingTransition 传统方式
这是最基础且兼容性最好的方法,适用于所有 Android 版本。
实现步骤:
- 创建动画资源文件 (res/anim/)
<!-- slide_in_right.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android"><translateandroid:duration="300"android:fromXDelta="100%p"android:toXDelta="0%p"android:interpolator="@android:anim/decelerate_interpolator"/>
</set><!-- slide_out_left.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android"><translateandroid:duration="300"android:fromXDelta="0%p"android:toXDelta="-100%p"android:interpolator="@android:anim/decelerate_interpolator"/>
</set><!-- fade_in.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android"><alphaandroid:duration="300"android:fromAlpha="0.0"android:toAlpha="1.0"android:interpolator="@android:anim/accelerate_interpolator"/>
</set>
- 在 Compose 中触发跳转
@Composable
fun FirstScreen() {val context = LocalContext.currentButton(onClick = {context.startActivity(Intent(context, SecondActivity::class.java))(context as Activity).overridePendingTransition(R.anim.slide_in_right, R.anim.fade_out)}) {Text("跳转到第二个Activity")}
}
- 在目标 Activity 中设置返回动画
class SecondActivity : ComponentActivity() {override fun finish() {super.finish()overridePendingTransition(R.anim.fade_in,R.anim.slide_out_left)}
}
2. 进阶动画组合
你可以组合多种动画效果:
<!-- slide_and_fade_in.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android"><translateandroid:duration="400"android:fromXDelta="20%"android:toXDelta="0%"android:interpolator="@android:anim/decelerate_interpolator"/><alphaandroid:duration="400"android:fromAlpha="0.0"android:toAlpha="1.0"android:interpolator="@android:anim/accelerate_interpolator"/><scaleandroid:duration="400"android:fromXScale="0.9"android:toXScale="1.0"android:fromYScale="0.9"android:toYScale="1.0"android:pivotX="50%"android:pivotY="50%"/>
</set>
二、共享元素过渡 (Android 5.0+)
1. 基本实现
共享元素过渡可以创建更流畅的视觉体验。
步骤1:在布局中定义过渡名称
@Composable
fun FirstScreen() {val context = LocalContext.currentval imageView = LocalView.currentColumn {Image(painter = rememberImagePainter(data = "https://example.com/image.jpg"),contentDescription = "共享图片",modifier = Modifier.size(200.dp).clickable {val intent = Intent(context, DetailActivity::class.java)val options = ActivityOptionsCompat.makeSceneTransitionAnimation(context as Activity,imageView,"shared_image" // 必须与DetailActivity中的名称一致)context.startActivity(intent, options.toBundle())}.composed {// 设置过渡名称ViewCompat.setTransitionName(imageView, "shared_image")Modifier})}
}
步骤2:在目标Activity中设置相同的过渡名称
class DetailActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {val imageView = LocalView.currentColumn {Image(painter = rememberImagePainter(data = "https://example.com/image.jpg"),contentDescription = "详情图片",modifier = Modifier.fillMaxWidth().aspectRatio(1f).composed {ViewCompat.setTransitionName(imageView, "shared_image")Modifier})}}}
}
2. 多个共享元素
// 启动Activity时
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,Pair(view1, "transition_title"),Pair(view2, "transition_image"),Pair(view3, "transition_bg")
)
startActivity(intent, options.toBundle())
三、高级过渡动画技巧
1. 使用 Material Motion 规范
Google 推荐的 Material Motion 过渡模式:
// 在styles.xml中定义主题继承
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight"><item name="android:windowActivityTransitions">true</item><item name="android:windowEnterTransition">@transition/explode</item><item name="android:windowExitTransition">@transition/explode</item><item name="android:windowSharedElementEnterTransition">@transition/change_image_transform</item><item name="android:windowSharedElementExitTransition">@transition/change_image_transform</item>
</style>// 过渡资源文件
<!-- change_image_transform.xml -->
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"><changeImageTransform/><changeBounds/><changeTransform/>
</transitionSet>
2. 延迟共享元素过渡
有时需要等待数据加载完成再开始过渡:
class DetailActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 延迟过渡直到数据加载完成postponeEnterTransition()setContent {val imageView = LocalView.currentLaunchedEffect(Unit) {// 模拟数据加载delay(1000)// 开始过渡动画startPostponedEnterTransition()}// 界面内容...}}
}
四、常见问题解决方案
1. 状态栏和导航栏过渡
// 在主题中添加
<item name="android:windowSharedElementsUseOverlay">false</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
2. 修复共享元素位置问题
// 在Compose中使用Modifier.clipToBounds()
Image(// ...modifier = Modifier.clipToBounds()
)
3. 自定义共享元素过渡
// 自定义SharedElementCallback
setExitSharedElementCallback(object : SharedElementCallback() {override fun onMapSharedElements(names: MutableList<String>,sharedElements: MutableMap<String, View>) {// 自定义映射逻辑}
})
五、性能优化建议
- 简化动画:避免过于复杂的动画效果
- 使用硬件加速:确保在manifest中启用了硬件加速
- 优化图片:共享元素中的图片应适当压缩
- 测试低端设备:确保动画在中低端设备上也能流畅运行
- 提供回退方案:为API<21的设备提供简单动画或直接跳转
六、完整示例代码
MainActivity.kt
class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {MyAppTheme {FirstScreen()}}}
}@Composable
fun FirstScreen() {val context = LocalContext.currentval imageView = LocalView.currentColumn(modifier = Modifier.fillMaxSize(),verticalArrangement = Arrangement.Center,horizontalAlignment = Alignment.CenterHorizontally) {// 简单跳转按钮Button(onClick = {context.startActivity(Intent(context, SimpleTransitionActivity::class.java))(context as Activity).overridePendingTransition(R.anim.slide_up,R.anim.stay)}) {Text("简单过渡效果")}Spacer(modifier = Modifier.height(16.dp))// 共享元素跳转Image(painter = rememberImagePainter(data = R.drawable.sample_image),contentDescription = "共享图片",modifier = Modifier.size(200.dp).clip(RoundedCornerShape(8.dp)).clickable {val intent = Intent(context, SharedElementActivity::class.java)val options = ActivityOptionsCompat.makeSceneTransitionAnimation(context as Activity,imageView,"shared_image")context.startActivity(intent, options.toBundle())}.composed {ViewCompat.setTransitionName(imageView, "shared_image")Modifier})}
}
SharedElementActivity.kt
class SharedElementActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)Window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)setContent {MyAppTheme {val imageView = LocalView.currentColumn(modifier = Modifier.fillMaxSize()) {Image(painter = rememberImagePainter(data = R.drawable.sample_image),contentDescription = "详情图片",modifier = Modifier.fillMaxWidth().aspectRatio(1f).padding(16.dp).clip(RoundedCornerShape(12.dp)).composed {ViewCompat.setTransitionName(imageView, "shared_image")Modifier})Spacer(modifier = Modifier.height(16.dp))Button(onClick = { finishAfterTransition() }) {Text("返回")}}}}}
}
通过以上方法,你可以在 Compose 项目中实现各种精美的 Activity 跳转动画效果。根据项目需求选择合适的方式,并注意测试不同设备和 Android 版本的兼容性。