Android Compose Activity 页面跳转动画详解

下面我将全面详细地介绍在 Compose 中实现 Activity 跳转动画的各种方法,包括基础实现、高级技巧和最佳实践。

一、基础 Activity 过渡动画

1. overridePendingTransition 传统方式

这是最基础且兼容性最好的方法,适用于所有 Android 版本。

实现步骤:

  1. 创建动画资源文件 (res/anim/)
xml 复制代码
<!-- slide_in_right.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android: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">
    <translate
        android: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">
    <alpha
        android:duration="300"
        android:fromAlpha="0.0"
        android:toAlpha="1.0"
        android:interpolator="@android:anim/accelerate_interpolator"/>
</set>
  1. 在 Compose 中触发跳转
kotlin 复制代码
@Composable
fun FirstScreen() {
    val context = LocalContext.current
    
    Button(
        onClick = {
            context.startActivity(Intent(context, SecondActivity::class.java))
            (context as Activity).overridePendingTransition(
                R.anim.slide_in_right, 
                R.anim.fade_out
            )
        }
    ) {
        Text("跳转到第二个Activity")
    }
}
  1. 在目标 Activity 中设置返回动画
kotlin 复制代码
class SecondActivity : ComponentActivity() {
    override fun finish() {
        super.finish()
        overridePendingTransition(
            R.anim.fade_in,
            R.anim.slide_out_left
        )
    }
}

2. 进阶动画组合

你可以组合多种动画效果:

xml 复制代码
<!-- slide_and_fade_in.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromXDelta="20%"
        android:toXDelta="0%"
        android:interpolator="@android:anim/decelerate_interpolator"/>
    <alpha
        android:duration="400"
        android:fromAlpha="0.0"
        android:toAlpha="1.0"
        android:interpolator="@android:anim/accelerate_interpolator"/>
    <scale
        android: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:在布局中定义过渡名称

kotlin 复制代码
@Composable
fun FirstScreen() {
    val context = LocalContext.current
    val imageView = LocalView.current
    
    Column {
        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中设置相同的过渡名称

kotlin 复制代码
class DetailActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        setContent {
            val imageView = LocalView.current
            
            Column {
                Image(
                    painter = rememberImagePainter(data = "https://example.com/image.jpg"),
                    contentDescription = "详情图片",
                    modifier = Modifier
                        .fillMaxWidth()
                        .aspectRatio(1f)
                        .composed {
                            ViewCompat.setTransitionName(imageView, "shared_image")
                            Modifier
                        }
                )
            }
        }
    }
}

2. 多个共享元素

kotlin 复制代码
// 启动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 过渡模式:

kotlin 复制代码
// 在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. 延迟共享元素过渡

有时需要等待数据加载完成再开始过渡:

kotlin 复制代码
class DetailActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 延迟过渡直到数据加载完成
        postponeEnterTransition()
        
        setContent {
            val imageView = LocalView.current
            
            LaunchedEffect(Unit) {
                // 模拟数据加载
                delay(1000)
                // 开始过渡动画
                startPostponedEnterTransition()
            }
            
            // 界面内容...
        }
    }
}

四、常见问题解决方案

1. 状态栏和导航栏过渡

kotlin 复制代码
// 在主题中添加
<item name="android:windowSharedElementsUseOverlay">false</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>

2. 修复共享元素位置问题

kotlin 复制代码
// 在Compose中使用Modifier.clipToBounds()
Image(
    // ...
    modifier = Modifier.clipToBounds()
)

3. 自定义共享元素过渡

java 复制代码
// 自定义SharedElementCallback
setExitSharedElementCallback(object : SharedElementCallback() {
    override fun onMapSharedElements(
        names: MutableList<String>,
        sharedElements: MutableMap<String, View>
    ) {
        // 自定义映射逻辑
    }
})

五、性能优化建议

  1. 简化动画:避免过于复杂的动画效果
  2. 使用硬件加速:确保在manifest中启用了硬件加速
  3. 优化图片:共享元素中的图片应适当压缩
  4. 测试低端设备:确保动画在中低端设备上也能流畅运行
  5. 提供回退方案:为API<21的设备提供简单动画或直接跳转

六、完整示例代码

MainActivity.kt

kotlin 复制代码
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyAppTheme {
                FirstScreen()
            }
        }
    }
}

@Composable
fun FirstScreen() {
    val context = LocalContext.current
    val imageView = LocalView.current
    
    Column(
        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

kotlin 复制代码
class SharedElementActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
        
        setContent {
            MyAppTheme {
                val imageView = LocalView.current
                
                Column(
                    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 版本的兼容性。

相关推荐
郁大锤2 小时前
Android Studio 国内镜像使用与 SDK 下载速度优化指南
android·ide·android studio
那就摆吧3 小时前
数据结构-栈
android·java·c语言·数据结构
奔跑吧 android3 小时前
【android bluetooth 框架分析 02】【Module详解 4】【Btaa 模块介绍】
android·bluetooth·bt·aosp13·btaa
Yang-Never3 小时前
ADB -> pull指令拉取手机文件到电脑上
android·adb·android studio
Yang-Never3 小时前
ADB -> pull指令推送电脑文件到手机上
android·adb·android studio
李新_3 小时前
我们封装了哪些好用的Flutter Mixin
android·flutter
帅次4 小时前
Flutter Expanded 与 Flexible 详解
android·flutter·ios·小程序·webview
流浪汉kylin4 小时前
Android手机如何腾出存储空间
android
0wioiw04 小时前
Kotlin基础(①)
android·开发语言·kotlin