You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jetpack Compose中实现Google Map全屏切换动画?

实现Google Map全屏切换动画的方案

核心思路

带垂直滚动的Column会限制子元素的高度(滚动容器的子项无法直接占满全屏),因此需要将全屏状态的地图从Column中独立出来,放在根布局的顶层,通过状态控制显示/隐藏,并添加过渡动画。

具体实现步骤

  1. 用remember定义全屏状态变量,控制地图的显示模式
  2. 根布局改用Box,同时容纳原滚动Column和全屏地图层
  3. 通过AnimatedVisibility给全屏地图添加平滑的进入/退出动画
  4. 让预览态和全屏态的地图共享同一个cameraPositionState,保持视角一致

修改后的完整代码

@Composable
fun YourScreen(
    innerPadding: PaddingValues,
    searchVM: SearchViewModel,
    navController: NavController,
    buttonList: ButtonList
) {
    var isFullScreen by remember { mutableStateOf(false) }
    val cameraPositionState = rememberCameraPositionState {
        position = CameraPosition.fromLatLngZoom(LatLng(37.7749, -122.4194), 10f)
    }

    // 根容器用Box,让全屏地图可覆盖在原内容之上
    Box(modifier = Modifier.fillMaxSize()) {
        // 原可滚动Column内容,全屏时透明隐藏
        Column(
            modifier = Modifier
                .verticalScroll(rememberScrollState())
                .fillMaxSize()
                .background(Color.Red.copy(alpha = 0.1f))
                .padding(innerPadding)
                .padding(horizontal = 5.dp)
                .alpha(if (isFullScreen) 0f else 1f)
        ) {
            Text(
                text = "Search",
                fontWeight = FontWeight.Bold,
                fontSize = 18.sp,
                modifier = Modifier.padding(5.dp)
            )

            SearchCard(
                state = searchVM,
                onEvent = searchVM,
            )

            Card(
                modifier = Modifier
                    .padding(horizontal = 30.dp, vertical = 10.dp)
                    .fillMaxWidth()
                    .height(40.dp),
                elevation = CardDefaults.cardElevation(defaultElevation = 15.dp),
                colors = CardDefaults.cardColors(containerColor = Color.White)
            ) {
                Column(
                    modifier = Modifier.fillMaxSize(),
                    verticalArrangement = Arrangement.Center,
                    horizontalAlignment = Alignment.CenterHorizontally
                ) {
                    Text(text = "Search", textAlign = TextAlign.Center)
                }
            }

            Text(
                text = "Map",
                fontWeight = FontWeight.Bold,
                fontSize = 18.sp,
                modifier = Modifier.padding(start = 5.dp)
            )

            // 预览态地图,全屏时隐藏
            AnimatedVisibility(visible = !isFullScreen) {
                Box(
                    modifier = Modifier
                        .size(400.dp)
                        .padding(10.dp)
                        .clip(shape = RoundedCornerShape(10.dp))
                ) {
                    GoogleMap(
                        modifier = Modifier.fillMaxSize(),
                        cameraPositionState = cameraPositionState
                    )
                    Box(
                        modifier = Modifier
                            .align(Alignment.TopEnd)
                            .padding(10.dp)
                    ) {
                        Icon(
                            imageVector = Icons.Default.Fullscreen,
                            contentDescription = "切换全屏",
                            modifier = Modifier
                                .size(30.dp)
                                .clickable {
                                    isFullScreen = true
                                }
                        )
                    }
                }
            }

            Text(
                text = "Hello",
                fontWeight = FontWeight.Bold,
                fontSize = 18.sp,
                modifier = Modifier.padding(start = 5.dp)
            )

            buttonList.list.chunked(2).forEach { rowItems ->
                ListCards(
                    searchVM = searchVM,
                    cardList = rowItems,
                    navController = navController
                )
            }

            SocialMediaAndAboutUs()
        }

        // 全屏态地图,默认隐藏,触发后带动画显示
        AnimatedVisibility(
            visible = isFullScreen,
            enter = fadeIn() + scaleIn(initialScale = 0.9f),
            exit = fadeOut() + scaleOut(targetScale = 0.9f)
        ) {
            Box(modifier = Modifier.fillMaxSize()) {
                GoogleMap(
                    modifier = Modifier.fillMaxSize(),
                    cameraPositionState = cameraPositionState
                )
                Box(
                    modifier = Modifier
                        .align(Alignment.TopEnd)
                        .padding(16.dp)
                ) {
                    Icon(
                        imageVector = Icons.Default.FullscreenExit,
                        contentDescription = "退出全屏",
                        tint = Color.White,
                        modifier = Modifier
                            .size(36.dp)
                            .background(Color.Black.copy(alpha = 0.5f), shape = CircleShape)
                            .padding(4.dp)
                            .clickable {
                                isFullScreen = false
                            }
                    )
                }
            }
        }
    }
}

关键细节说明

  • 根容器用Box:突破Column的滚动约束,让全屏地图可以覆盖整个界面
  • 动画效果:通过AnimatedVisibility的enter/exit参数实现淡入淡出+缩放的平滑过渡,可根据需求替换为滑动、旋转等其他动画
  • 共享地图状态:复用同一个cameraPositionState,保证预览和全屏模式下地图视角无缝衔接
  • 原内容隐藏方式:用alpha过渡替代直接隐藏,让切换过程更自然

内容的提问来源于stack exchange,提问作者Pawandeep Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 01:54:53