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 compose屏幕适配终极解决方案
android
2501_916007473 小时前
HTTPS 抓包乱码怎么办?原因剖析、排查步骤与实战工具对策(HTTPS 抓包乱码、gzipbrotli、TLS 解密、iOS 抓包)
android·ios·小程序·https·uni-app·iphone·webview
feiyangqingyun4 小时前
基于Qt和FFmpeg的安卓监控模拟器/手机摄像头模拟成onvif和28181设备
android·qt·ffmpeg
用户2018792831678 小时前
ANR之RenderThread不可中断睡眠state=D
android
煤球王子8 小时前
简单学:Android14中的Bluetooth—PBAP下载
android
小趴菜82278 小时前
安卓接入Max广告源
android
齊家治國平天下8 小时前
Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
android·anr
ZHANG13HAO8 小时前
Android 13.0 Framework 实现应用通知使用权默认开启的技术指南
android
【ql君】qlexcel8 小时前
Android 安卓RIL介绍
android·安卓·ril
写点啥呢8 小时前
android12解决非CarProperty接口深色模式设置后开机无法保持
android·车机·aosp·深色模式·座舱