界面优先级存在部分问题,先锁定到这个版本,进行后续优化

This commit is contained in:
2026-08-19 21:32:54 +08:00
parent 85463c3716
commit d116814bb6
3 changed files with 206 additions and 81 deletions
+50 -36
View File
@@ -6,11 +6,9 @@ import 'services/audio_service.dart';
import 'services/playback_service.dart'; import 'services/playback_service.dart';
import 'pages/home_page.dart'; import 'pages/home_page.dart';
import 'pages/player_page.dart'; import 'pages/player_page.dart';
import 'pages/playlist_page.dart'; // ✅ 导入 PlaylistPage import 'pages/playlist_page.dart';
import 'widgets/global_mini_player.dart'; import 'widgets/global_mini_player.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
void main() { void main() {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
@@ -55,7 +53,7 @@ class QTPlayerApp extends StatefulWidget {
class _QTPlayerAppState extends State<QTPlayerApp> class _QTPlayerAppState extends State<QTPlayerApp>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
bool _showPlayerPage = false; bool _showPlayerPage = false;
bool _showPlaylist = false; // ✅ 新增:播放列表显示状态 bool _showPlaylist = false;
late final AnimationController _animationController; late final AnimationController _animationController;
late final Animation<double> _slideAnimation; late final Animation<double> _slideAnimation;
@@ -88,33 +86,56 @@ class _QTPlayerAppState extends State<QTPlayerApp>
void _openPlayerPage() { void _openPlayerPage() {
setState(() { setState(() {
_showPlayerPage = true; _showPlayerPage = true;
_showPlaylist = false; // 打开播放页时关闭播放列表 _showPlaylist = false;
}); });
_animationController.forward(from: 0.0); _animationController.forward(from: 0.0);
} }
void _closePlayerPage() { void _closePlayerPage() {
_animationController.reverse().then((_) { _animationController.reverse().then((_) {
if (mounted) {
setState(() { setState(() {
_showPlayerPage = false; _showPlayerPage = false;
}); });
}
}); });
} }
// ✅ 打开播放列表
void _openPlaylist() { void _openPlaylist() {
setState(() { setState(() {
_showPlaylist = true; _showPlaylist = true;
}); });
} }
// ✅ 关闭播放列表
void _closePlaylist() { void _closePlaylist() {
setState(() { setState(() {
_showPlaylist = false; _showPlaylist = false;
}); });
} }
// ============================================================
// ✅ PopScope 的 onPopInvokedWithResult
// ============================================================
void _onPopInvokedWithResult(bool didPop, Object? result) {
if (didPop) return;
// 1️⃣ 优先关闭播放列表(最高层级)
if (_showPlaylist) {
_closePlaylist();
return;
}
// 2️⃣ 其次关闭播放页
if (_showPlayerPage) {
_closePlayerPage();
return;
}
// 3️⃣ 没有覆盖层,允许退出(由 Navigator 处理)
// 注意:这里不能直接退出,需要让 Navigator 处理
// 但 canPop 会根据状态返回 true/false
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (!widget.initSuccess) { if (!widget.initSuccess) {
@@ -137,25 +158,6 @@ class _QTPlayerAppState extends State<QTPlayerApp>
style: TextStyle(color: Colors.grey[400], fontSize: 14), style: TextStyle(color: Colors.grey[400], fontSize: 14),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
runApp(
ChangeNotifierProvider(
create: (_) => AudioService(),
child: QTPlayerApp(
initSuccess: true,
initError: null,
),
),
);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFB8D4D0),
foregroundColor: Colors.black87,
),
child: const Text('重试'),
),
], ],
), ),
), ),
@@ -165,7 +167,6 @@ class _QTPlayerAppState extends State<QTPlayerApp>
return MaterialApp( return MaterialApp(
title: '清听', title: '清听',
navigatorKey: navigatorKey,
theme: ThemeData( theme: ThemeData(
brightness: Brightness.dark, brightness: Brightness.dark,
primaryColor: const Color(0xFF7C9A9E), primaryColor: const Color(0xFF7C9A9E),
@@ -179,23 +180,37 @@ class _QTPlayerAppState extends State<QTPlayerApp>
), ),
home: const HomePage(), home: const HomePage(),
builder: (context, child) { builder: (context, child) {
return Overlay( // ✅ 暴力测试:canPop 写死为 false
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
debugPrint('🔥🔥🔥 BACK FIRED: didPop=$didPop');
debugPrint('🔥 playlist=$_showPlaylist, player=$_showPlayerPage');
if (_showPlaylist) {
debugPrint('🔥 closing playlist');
_closePlaylist();
} else if (_showPlayerPage) {
debugPrint('🔥 closing player');
_closePlayerPage();
} else {
debugPrint('🔥 no overlay, allowing exit');
// 注意:这里 canPop=false,需要手动退出
// 用 SystemNavigator.pop() 或 Navigator.pop(context)
}
},
child: Overlay(
initialEntries: [ initialEntries: [
OverlayEntry( OverlayEntry(
builder: (context) => Stack( builder: (context) => Stack(
children: [ children: [
// ① 主页面
Positioned.fill(child: child!), Positioned.fill(child: child!),
// ② MiniPlayer
const Positioned( const Positioned(
left: 0, left: 0,
right: 0, right: 0,
bottom: 0, bottom: 0,
child: GlobalMiniPlayer(), child: GlobalMiniPlayer(),
), ),
// ③ 播放页(全屏覆盖)
if (_showPlayerPage) if (_showPlayerPage)
Positioned.fill( Positioned.fill(
child: AnimatedBuilder( child: AnimatedBuilder(
@@ -214,12 +229,10 @@ class _QTPlayerAppState extends State<QTPlayerApp>
}, },
child: PlayerPage( child: PlayerPage(
onClose: _closePlayerPage, onClose: _closePlayerPage,
onOpenPlaylist: _openPlaylist, // ✅ 传入回调 onOpenPlaylist: _openPlaylist,
), ),
), ),
), ),
// ④ ✅ 播放列表(最高层级,在播放页之上)
if (_showPlaylist) if (_showPlaylist)
Positioned.fill( Positioned.fill(
child: PlaylistPage( child: PlaylistPage(
@@ -230,6 +243,7 @@ class _QTPlayerAppState extends State<QTPlayerApp>
), ),
), ),
], ],
),
); );
}, },
); );
+114
View File
@@ -0,0 +1,114 @@
// lib/pages/shell_page.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../services/audio_service.dart';
import '../widgets/global_mini_player.dart';
import 'home_page.dart';
import 'player_page.dart';
import 'playlist_page.dart';
class ShellPage extends StatefulWidget {
const ShellPage({super.key});
@override
State<ShellPage> createState() => _ShellPageState();
}
class _ShellPageState extends State<ShellPage> {
// ✅ 从 PlayerPage 打开 PlaylistPage
void _openPlaylistFromPlayer() {
Navigator.pushNamed(context, '/playlist');
}
// ✅ 关闭 PlayerPage
void _closePlayer() {
Navigator.pop(context);
}
// ✅ 关闭 PlaylistPage
void _closePlaylist() {
Navigator.pop(context);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF0E1211),
body: Stack(
children: [
// ---- 页面内容(Navigator ----
Navigator(
initialRoute: '/',
onGenerateRoute: (settings) {
switch (settings.name) {
case '/':
return _buildPageRoute(
const HomePage(),
settings: settings,
);
case '/player':
return _buildPageRoute(
PlayerPage(
onClose: _closePlayer,
onOpenPlaylist: _openPlaylistFromPlayer,
),
settings: settings,
fromBottom: true,
);
case '/playlist':
return _buildPageRoute(
PlaylistPage(
onClose: _closePlaylist,
),
settings: settings,
);
default:
return null;
}
},
),
// ---- MiniPlayer(覆盖在最上层) ----
const Positioned(
left: 0,
right: 0,
bottom: 0,
child: GlobalMiniPlayer(),
),
],
),
);
}
PageRouteBuilder _buildPageRoute(
Widget page, {
required RouteSettings settings,
bool fromBottom = false,
}) {
return PageRouteBuilder(
settings: settings,
pageBuilder: (context, animation, secondaryAnimation) => page,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
if (fromBottom) {
// 播放页:从底部滑入
final offset = Tween<Offset>(
begin: const Offset(0, 1),
end: Offset.zero,
).animate(CurvedAnimation(
parent: animation,
curve: Curves.easeOutCubic,
));
return SlideTransition(position: offset, child: child);
} else {
// 其他页面:淡入
return FadeTransition(
opacity: animation,
child: child,
);
}
},
transitionDuration: const Duration(milliseconds: 300),
reverseTransitionDuration: const Duration(milliseconds: 300),
);
}
}
+2 -5
View File
@@ -2,15 +2,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../services/audio_service.dart'; import '../services/audio_service.dart';
import '../main.dart';
class GlobalMiniPlayer extends StatelessWidget { class GlobalMiniPlayer extends StatelessWidget {
const GlobalMiniPlayer({super.key}); const GlobalMiniPlayer({super.key});
// ✅ 全局回调:打开播放页 // ✅ 保留静态回调
static VoidCallback? onOpenPlayerPage; static VoidCallback? onOpenPlayerPage;
// ✅ 新增:打开播放列表
static VoidCallback? onOpenPlaylistPage; static VoidCallback? onOpenPlaylistPage;
@override @override
@@ -114,7 +111,7 @@ class GlobalMiniPlayer extends StatelessWidget {
size: 24, size: 24,
), ),
onPressed: () { onPressed: () {
// ✅ 使用回调打开播放列表(与播放页同一套层级) // ✅ 使用静态回调,而不是 Navigator.pushNamed
if (onOpenPlaylistPage != null) { if (onOpenPlaylistPage != null) {
onOpenPlaylistPage!(); onOpenPlaylistPage!();
} }