style(ui): 播放页指示器改为"当前页长条"样式 + 补齐底部安全区

指示器(按设计稿):
- 三段:左点 / 中条 / 右点
- 当前页对应的段展开为 30x7 长条并高亮白色,
  另外两段收起为 7x7 小点(暗)
- 主页=中间长条,信息页=左长条,歌词页=右长条,220ms 动画过渡
- 点击任一段可直接跳到对应页

安全区:
- PageView 外层包 SafeArea(top: false),
  控制按钮不再贴着 mback 手势区
This commit is contained in:
2026-10-31 22:59:27 +08:00
parent 7cd1e13a82
commit abe960cf58
+20 -14
View File
@@ -249,7 +249,9 @@ class _PlayerPageState extends BaseState<PlayerPage> {
),
],
),
body: PageView(
body: SafeArea(
top: false,
child: PageView(
controller: _pageController,
onPageChanged: (index) => setState(() => _pageIndex = index),
children: [
@@ -258,12 +260,14 @@ class _PlayerPageState extends BaseState<PlayerPage> {
_buildLyricsPage(song),
],
),
),
);
}
/// 顶部两点指示器:左点=信息页,右点=歌词页,中间不亮表示在主页
/// 顶部指示器:当前页对应"长条",另外两页是小点。
/// 主页=中间长条,信息页=左长条,歌词页=右长条。
Widget _buildPageIndicator() {
Widget dot(int index) {
Widget segment(int index) {
final active = _pageIndex == index;
return GestureDetector(
onTap: () => _pageController.animateToPage(
@@ -271,13 +275,18 @@ class _PlayerPageState extends BaseState<PlayerPage> {
duration: const Duration(milliseconds: 280),
curve: Curves.easeOutCubic,
),
behavior: HitTestBehavior.opaque,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 2),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
width: 7,
duration: const Duration(milliseconds: 220),
curve: Curves.easeOutCubic,
width: active ? 30 : 7,
height: 7,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: active ? Colors.white : Colors.white24,
borderRadius: BorderRadius.circular(4),
),
),
),
);
@@ -286,14 +295,11 @@ class _PlayerPageState extends BaseState<PlayerPage> {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
dot(0),
Container(
width: 56,
height: 1,
margin: const EdgeInsets.symmetric(horizontal: 8),
color: Colors.white12,
),
dot(2),
segment(0),
const SizedBox(width: 6),
segment(1),
const SizedBox(width: 6),
segment(2),
],
);
}