You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 04:25:17