可折叠底栏 —— 原型说明 & 接入指南
Apple Music 风格:底部 Tab Bar 和 MiniPlayer 在滚动时从两行压成一行,回到顶部松手自动展开,点击折叠态的 Tab 图标也能展开。
原型文件
位置:app/src/main/java/io/kyonqi/musicplayer/prototype/
| 文件 | 作用 |
|---|---|
CollapsibleBottomBarState.kt |
折叠进度 State + NestedScrollConnection |
CollapsibleBottomBarScaffold.kt |
布局脚手架(展开/折叠两种布局 + 动画) |
PrototypeScreen.kt |
可跑的 Demo(含 DemoMiniPlayer) |
跑原型
在 MainActivity 里临时替换:
1 | setContent { |
接入真实 App
1. 给 MiniPlayer 加 compact 参数
ui/component/MiniPlayer.kt:
1 |
|
关键:外层 Surface/shape/padding 全由 CollapsibleBottomBarScaffold 提供,MiniPlayer 内部只渲染内容。
2. 改造 AppNavigation.kt
把 Scaffold { bottomBar = Column { MiniPlayer + LibraryBottomBar } } 整个换成 CollapsibleBottomBarScaffold:
1 |
|
3. 让每个 Tab 屏幕把 bottomPadding 应用到列表
以 SongListScreen 为例,给它加一个 bottomPadding: Dp = 0.dp 参数,传给内层 LazyColumn 的 contentPadding:
1 | fun SongListScreen( |
AlbumListScreen / ArtistListScreen / FolderBrowserScreen 同理。
4. 回弹展开(每个 Tab 屏幕内)
把这段 LaunchedEffect 放到每个 Tab 屏幕的 LazyListState 旁边,让列表滚到顶部停手后自动展开底栏:
1 | // 在每个 Tab 的 Composable 里: |
为了不把 state 层层传到每个 Tab,加一个 CompositionLocal:
1 | // 放在 CollapsibleBottomBarState.kt |
在 Scaffold 里把 state 通过 CompositionLocalProvider 下发:
1 | // 在 CollapsibleBottomBarScaffold 的 content 调用处: |
5. 清理旧代码
删除 AppNavigation 里:
- 外层
Scaffold LibraryBottomBar私有 composable(被CollapsibleBottomBarScaffold内部的 Tab 代替)- 注释掉的旧代码块(第 202-256 行)
AnimatedVisibility(showTabBar) { Column { MiniPlayer ... } }整个结构
navigateToTab 扩展保留,Routes 常量保留。
6. 可选:搜索页
加路由:
1 | // Routes |
搜索页不在 TabRoutes 里,所以 showBar = false,全屏显示。
联动注意事项
- LargeTopAppBar 共存:Tab 屏幕里用
LargeTopAppBar(scrollBehavior=…)时,它自己的 NestedScrollConnection 与底栏的 connection 都会看到滚动事件,互不冲突——上滑时两个都会缩起来,正是我们要的行为。 - 多 Tab 切换保持 state:
CollapsibleBottomBarState由外层 scaffold 持有,切 Tab 时不重建,进度保持。但切 Tab 后列表滚到顶,建议在切 Tab 的回调里顺手state.expandNow()(体验更一致)。 - WindowInsets:如果手势导航的 bottom inset 要处理,在
Box(modifier = Modifier.fillMaxWidth().height(containerHeight)…)上加.windowInsetsPadding(WindowInsets.navigationBars)。 - NowPlaying 转场:你原来用
slideIntoContainer(Up)的切换动画保留即可,底栏因为showBar=false会被AnimatedVisibility的slideOutVertically顺带滑出去,视觉统一。
已知局限
- 交叉淡化在中点 (
p ≈ 0.5) 仍有极短的两套布局共存窗口(靠 slide + stagger alpha 掩盖)。要达到真·Apple Music 那种同一元素的连续 morph,需要改用LookaheadLayout或共享元素过渡,复杂度翻倍,暂未做。 - 松手时若速度为 0、停在半途,
onPreFling仍会被调用处理吸附——这点已经覆盖。 - 搜索按钮在折叠态和展开态尺寸不一致(展开态在 TabRow 右侧 48dp,折叠态独立 52dp)。若强迫症可把两处统一成同尺寸。
说些什么吧!