style(ui): 播放页间距等宽 + 控制行上移 25 + 进度条重写
- 标题/歌手/专辑的间距统一为 10,视感更整齐 - 底部留白 70 -> 45(控制行上移 25) - 进度条改用 LayoutBuilder + Positioned 绝对宽度, 背景/缓冲/已播三层顺序明确,不再出现两端亮块
This commit is contained in:
+82
-65
@@ -308,7 +308,7 @@ class _PlayerPageState extends BaseState<PlayerPage> {
|
||||
Widget _buildMainPage(AudioService service, Song song, bool isPlaying) {
|
||||
return Padding(
|
||||
// 顶部留 16:与 AppBar/指示器拉开距离,避免封面贴着顶部
|
||||
padding: const EdgeInsets.fromLTRB(24, 16, 24, 0),
|
||||
padding: const EdgeInsets.fromLTRB(24, 24, 24, 0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -366,17 +366,17 @@ class _PlayerPageState extends BaseState<PlayerPage> {
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
song.artist,
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey[400]),
|
||||
style: TextStyle(fontSize: 16, color: Colors.grey[300]),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
||||
// ---- 信息区(专辑 / 目录)----
|
||||
if (_album.isNotEmpty || _folder.isNotEmpty) ...[
|
||||
const SizedBox(height: 14),
|
||||
const SizedBox(height: 10),
|
||||
if (_album.isNotEmpty)
|
||||
Text(
|
||||
_album,
|
||||
@@ -409,7 +409,8 @@ class _PlayerPageState extends BaseState<PlayerPage> {
|
||||
|
||||
// ---- 控制 ----
|
||||
_buildControlButtons(service, song, isPlaying),
|
||||
const SizedBox(height: 20),
|
||||
// 底部多留 50px:控制行整体上移
|
||||
const SizedBox(height: 45),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -548,70 +549,86 @@ class _PlayerPageState extends BaseState<PlayerPage> {
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 24,
|
||||
child: Stack(
|
||||
alignment: Alignment.centerLeft,
|
||||
children: [
|
||||
Container(
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[800],
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
FractionallySizedBox(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final width = constraints.maxWidth;
|
||||
return Stack(
|
||||
alignment: Alignment.centerLeft,
|
||||
widthFactor: bufferProgress.clamp(0.0, 1.0),
|
||||
child: Container(
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF4A7A7A),
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
),
|
||||
FractionallySizedBox(
|
||||
alignment: Alignment.centerLeft,
|
||||
widthFactor: displayProgress.clamp(0.0, 1.0),
|
||||
child: Container(
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFB8D4D0),
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
trackHeight: 0,
|
||||
activeTrackColor: Colors.transparent,
|
||||
inactiveTrackColor: Colors.transparent,
|
||||
thumbColor: Colors.transparent,
|
||||
overlayColor: Colors.transparent,
|
||||
thumbShape: const RoundSliderThumbShape(
|
||||
enabledThumbRadius: 0,
|
||||
children: [
|
||||
// 背景轨道
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 10.5,
|
||||
child: Container(
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[800],
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Slider(
|
||||
value: displayProgress.clamp(0.0, 1.0),
|
||||
min: 0.0,
|
||||
max: 1.0,
|
||||
onChanged: (value) {
|
||||
setState(() => _dragProgress = value);
|
||||
},
|
||||
onChangeEnd: (value) {
|
||||
final newPosition = Duration(
|
||||
milliseconds:
|
||||
(value * duration.inMilliseconds)
|
||||
.round(),
|
||||
);
|
||||
service.seekTo(newPosition);
|
||||
setState(() => _dragProgress = null);
|
||||
},
|
||||
// 已缓冲
|
||||
Positioned(
|
||||
left: 0,
|
||||
top: 10.5,
|
||||
child: Container(
|
||||
width: width * bufferProgress.clamp(0.0, 1.0),
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF4A7A7A),
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
// 已播放
|
||||
Positioned(
|
||||
left: 0,
|
||||
top: 10.5,
|
||||
child: Container(
|
||||
width:
|
||||
width * displayProgress.clamp(0.0, 1.0),
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFB8D4D0),
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
trackHeight: 0,
|
||||
activeTrackColor: Colors.transparent,
|
||||
inactiveTrackColor: Colors.transparent,
|
||||
thumbColor: Colors.transparent,
|
||||
overlayColor: Colors.transparent,
|
||||
thumbShape: const RoundSliderThumbShape(
|
||||
enabledThumbRadius: 0,
|
||||
),
|
||||
),
|
||||
child: Slider(
|
||||
value: displayProgress.clamp(0.0, 1.0),
|
||||
min: 0.0,
|
||||
max: 1.0,
|
||||
onChanged: (value) {
|
||||
setState(() => _dragProgress = value);
|
||||
},
|
||||
onChangeEnd: (value) {
|
||||
final newPosition = Duration(
|
||||
milliseconds:
|
||||
(value * duration.inMilliseconds)
|
||||
.round(),
|
||||
);
|
||||
service.seekTo(newPosition);
|
||||
setState(() => _dragProgress = null);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user