Flutter中YouTube播放器页面WillPopScope失效问题排查
问题分析
WillPopScope失效的核心原因是youtube_player_flutter库在全屏模式下会拦截系统返回事件,同时你的WillPopScope没有正确处理全屏状态下的返回逻辑,另外onWillPop的写法存在冲突(手动调用Navigator.pop()后返回false,可能导致系统返回事件被异常阻断)。
解决方案
1. 修正WillPopScope逻辑,优先处理全屏状态
修改onWillPop回调,先判断视频是否处于全屏模式:如果是,先退出全屏;如果不是,再恢复屏幕方向并允许系统执行pop操作。
2. 确保WillPopScope层级正确
将WillPopScope直接包裹在页面根组件外层,保证能捕获到返回事件。
3. 添加控制器监听(增强状态同步)
监听YoutubePlayerController的全屏状态变化,确保屏幕方向和页面状态同步。
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:stocker/models/YouTubeStateModel.dart'; import 'package:youtube_player_flutter/youtube_player_flutter.dart'; class VideoPlayer extends StatefulWidget { const VideoPlayer({ Key? key, required this.videoID, required this.data, }) : super(key: key); static const routeName = '/videoPlayer'; final YouTubeState data; final String videoID; @override State<VideoPlayer> createState() => _VideoPlayerState(); } class _VideoPlayerState extends State<VideoPlayer> { late YoutubePlayerController _controller; @override void initState() { super.initState(); _controller = YoutubePlayerController( initialVideoId: widget.videoID, flags: const YoutubePlayerFlags( autoPlay: true, mute: false, ), ); // 监听全屏状态,同步屏幕方向 _controller.addListener(() { if (_controller.value.isFullScreen) { SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); } else { SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, ]); } }); Future.delayed(const Duration(milliseconds: 300)).then((value) { _controller.toggleFullScreenMode(); _controller.setSize(Size(1.sw, 1.sh)); }); } @override void dispose() { _controller.dispose(); // 页面销毁时强制恢复竖屏 SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); super.dispose(); } @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; final width = size.width; final height = size.height; _controller.setSize( width > height ? Size(1.sw - ScreenUtil().statusBarHeight, 1.sh) : Size(1.sw, 1.sh - ScreenUtil().statusBarHeight), ); return WillPopScope( onWillPop: () async { if (_controller.value.isFullScreen) { // 全屏时先退出全屏,不执行页面pop _controller.toggleFullScreenMode(); return false; } else { // 非全屏时恢复竖屏,允许系统执行pop SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); return true; } }, child: Stack( children: [ YoutubePlayerBuilder( player: YoutubePlayer( bottomActions: [ const SizedBox(width: 14.0), CurrentPosition(), const SizedBox(width: 8.0), ProgressBar(isExpanded: true), RemainingDuration(), const PlaybackSpeedButton(), ], aspectRatio: width > height ? height / (width - ScreenUtil().statusBarHeight) : (height - ScreenUtil().statusBarHeight) / width, controller: _controller, width: size.width, ), builder: (context, player) { return Scaffold( backgroundColor: Colors.black, body: Padding( padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight), child: SizedBox( height: 1.sh - ScreenUtil().statusBarHeight, width: 1.sw, child: Stack( children: [ Center(child: player), ], ), ), ), ); }, ), Positioned( left: 5.w, top: 30.h, child: GestureDetector( onTap: () { if (_controller.value.isFullScreen) { _controller.toggleFullScreenMode(); } else { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); Navigator.of(context).pop(); } }, child: SvgPicture.asset( 'assets/svg/back_arrow.svg', color: Colors.white, width: 16.w, height: 16.w, ), ), ) ], ), ); } }
额外检查路由配置
如果上述修改后仍无效,确认main.dart中的路由配置是否正确:
- 使用
onGenerateRoute传递必填参数:
// MaterialApp内部配置 onGenerateRoute: (settings) { if (settings.name == VideoPlayer.routeName) { final args = settings.arguments as Map<String, dynamic>; return MaterialPageRoute( builder: (context) => VideoPlayer( videoID: args['videoID'] as String, data: args['data'] as YouTubeState, ), ); } return MaterialPageRoute(builder: (context) => const HomePage()); }
- 跳转时正确传参:
Navigator.pushNamed( context, VideoPlayer.routeName, arguments: { 'videoID': '目标视频ID', 'data': 你的YouTubeState实例, }, );
内容的提问来源于stack exchange,提问作者Mussadaq Ahmad Jamil
相关产品推荐
相关产品推荐

