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

在Android Jetpack Compose中实现带底部导航栏的类YouTube音乐迷你播放器

解决方案与实现步骤

针对你在Material3中遇到的BottomSheetScaffold与底部导航栏配合、Sheet内容切换的问题,核心思路是将带底部导航的Scaffold嵌套进BottomSheetScaffold的内容区域,通过Sheet状态控制导航栏的显隐,同时利用Sheet的折叠高度实现Mini Player与Now Playing的切换,完全贴合YouTube/YouTube Music的交互逻辑。

核心实现要点

  1. Sheet状态管理:使用rememberBottomSheetState区分PartiallyExpanded(折叠,显示Mini Player)、Expanded(展开,显示Now Playing)两种核心状态,关闭隐藏状态的跳过逻辑,确保状态切换可控。
  2. 导航栏显隐控制:通过Sheet状态判断是否显示底部导航栏,配合动画实现平滑过渡。
  3. Sheet内容切换:根据当前Sheet状态,在sheetContent中渲染对应的Mini Player或Now Playing界面,折叠高度设置为Mini Player的固定高度。

完整代码示例

@Composable
fun MainScreen() {
    // 初始化Sheet状态,默认折叠,允许切换到隐藏状态(可选)
    val sheetState = rememberBottomSheetState(
        initialValue = BottomSheetValue.PartiallyExpanded,
        skipHiddenState = false,
        confirmValueChange = { newValue ->
            // 可在这里添加状态切换的拦截逻辑,比如禁止播放中隐藏Sheet
            true
        }
    )
    val coroutineScope = rememberCoroutineScope()

    BottomSheetScaffold(
        sheetState = sheetState,
        // 设置折叠时的高度为Mini Player的标准高度
        sheetPeekHeight = 64.dp,
        // Material3风格的Sheet圆角
        sheetShape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
        sheetContent = {
            when (sheetState.currentValue) {
                BottomSheetValue.Expanded -> {
                    // 展开时显示Now Playing全屏界面
                    NowPlayingScreen(
                        onCollapseClick = {
                            coroutineScope.launch {
                                sheetState.partialExpand()
                            }
                        }
                    )
                }
                BottomSheetValue.PartiallyExpanded -> {
                    // 折叠时显示Mini Player,点击触发展开
                    MiniPlayerScreen(
                        onClick = {
                            coroutineScope.launch {
                                sheetState.expand()
                            }
                        }
                    )
                }
                // 隐藏状态下可留空或显示占位
                BottomSheetValue.Hidden -> {}
            }
        }
    ) { innerPadding ->
        // 嵌套带底部导航的Scaffold作为主内容区域
        Scaffold(
            bottomBar = {
                // 仅当Sheet处于折叠状态时显示导航栏,添加动画过渡
                AnimatedVisibility(
                    visible = sheetState.currentValue == BottomSheetValue.PartiallyExpanded,
                    enter = slideInVertically(initialOffsetY = { it }),
                    exit = slideOutVertically(targetOffsetY = { it })
                ) {
                    BottomNavigation(
                        containerColor = MaterialTheme.colorScheme.surfaceContainer
                    ) {
                        // 导航项示例
                        BottomNavigationItem(
                            selected = false,
                            onClick = {},
                            icon = { Icon(Icons.Default.Home, contentDescription = "Home") },
                            label = { Text("Home") }
                        )
                        BottomNavigationItem(
                            selected = false,
                            onClick = {},
                            icon = { Icon(Icons.Default.LibraryMusic, contentDescription = "Library") },
                            label = { Text("Library") }
                        )
                    }
                }
            }
        ) { scaffoldPadding ->
            // 主页面内容,比如首页、库页等
            Box(
                modifier = Modifier
                    .padding(innerPadding)
                    .padding(scaffoldPadding)
                    .fillMaxSize(),
                contentAlignment = Alignment.Center
            ) {
                Text("Main Content Area")
            }
        }
    }
}

// 示例Mini Player组件
@Composable
fun MiniPlayerScreen(onClick: () -> Unit) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .height(64.dp)
            .clickable(onClick = onClick)
            .padding(horizontal = 16.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.SpaceBetween
    ) {
        Icon(Icons.Default.MusicNote, contentDescription = "Playing")
        Text("Current Track Name", style = MaterialTheme.typography.bodyLarge)
        Icon(Icons.Default.PlayArrow, contentDescription = "Play")
    }
}

// 示例Now Playing组件
@Composable
fun NowPlayingScreen(onCollapseClick: () -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Icon(Icons.Default.MusicNote, contentDescription = "Now Playing", modifier = Modifier.size(128.dp))
        Text("Full Now Playing Screen", style = MaterialTheme.typography.headlineMedium)
        Spacer(modifier = Modifier.height(32.dp))
        Button(onClick = onCollapseClick) {
            Text("Collapse")
        }
    }
}

关键优化细节

  • 动画过渡:使用AnimatedVisibility给导航栏添加滑入滑出动画,提升交互流畅度。
  • 状态监听:可通过LaunchedEffect监听sheetState.currentValue变化,触发播放状态同步(比如展开时显示歌词、折叠时仅显示控制按钮)。
  • Sheet行为定制:通过confirmValueChange参数拦截状态切换,比如禁止在播放中隐藏Sheet。
  • Material3风格适配:设置sheetShape为圆角,符合Material3的组件规范。

内容的提问来源于stack exchange,提问作者Curious Head

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 07:18:23