如何在Chewie控制器全屏播放时通过滚动触发操作?
问题:Chewie全屏状态下无法触发滚动手势切换视频
我想要实现:在Chewie控制器全屏播放视频时,通过向下滚动手势切换到另一个视频。目前已将播放器包裹在GestureDetector中,并为Chewie控制器添加了监听器,但全屏状态下panUpdate事件完全无响应。
以下是我的代码:
import 'dart:math'; import 'package:chewie/chewie.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:video_player/video_player.dart'; import 'package:visibility_detector/visibility_detector.dart'; import '../screens/mainScreen.dart'; class ChewieVideoWidget extends Stateful Widget { final String asset; final bool autoPlay; ChewieVideoWidget(this.asset, this.autoPlay); @override _ChewieVideoWidgetState createState() => _ChewieVideoWidgetState(); } class _ChewieVideoWidgetState extends State<ChewieVideoWidget> { late ChewieController chewieController; late VideoPlayerController videoPlayerController; bool _isPlaying = false; @override void initState() { super.initState(); videoPlayerController = VideoPlayerController.asset(widget.asset); chewieController = ChewieController( videoPlayerController: videoPlayerController, autoPlay: widget.autoPlay, aspectRatio: 16 / 9, autoInitialize: true, errorBuilder: (context, errorMessage) { return Center( child: Text( errorMessage, style: const TextStyle(color: Colors.white), ), ); }, customControls: const MaterialControls(), materialProgressColors: ChewieProgressColors( playedColor: Colors.lightBlue, handleColor: Colors.white, bufferedColor: Colors.white.withOpacity(0.5), backgroundColor: Colors.grey.withOpacity(.5), ), ); chewieController.addListener(() { print("FULL SCREEN:${chewieController.isFullScreen}"); }); Future.delayed(Duration.zero, () { chewieController.deviceOrientationsOnEnterFullScreen = [ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight ]; chewieController.deviceOrientationsAfterFullScreen = [ DeviceOrientation.portraitUp ]; }); } @override void dispose() { chewieController.pause(); chewieController.dispose(); videoPlayerController.dispose(); print('chewie disposed'); super.dispose(); } @override Widget build(BuildContext context) { return VisibilityDetector( key: Key(Random().toString()), onVisibilityChanged: (VisibilityInfo info) { if (info.visibleFraction <= 0.9 && mounted) { chewieController.pause(); } }, child: GestureDetector( onPanUpdate: (details) { if (chewieController.isFullScreen == true) { if (details.delta.dy < -5) { Navigator.of(context).push( MaterialPageRoute<void>( builder: (BuildContext context) => MainScreen(1), ), ); } } }, child: AspectRatio( aspectRatio: 16 / 9, child: Chewie( controller: chewieController, ), ), ), ); } }
解决方案
问题根源
Chewie进入全屏时,会将视频播放器组件挂载到一个独立的全屏Route中,而你原来的GestureDetector仅包裹在非全屏状态的Chewie外层,并不属于这个新的全屏Route层级,因此无法捕获全屏时的手势事件。
方法1:利用fullScreenPlaceholder添加全屏手势
直接通过ChewieController的fullScreenPlaceholder参数,为全屏状态的播放器添加手势检测:
// 修改ChewieController初始化代码 chewieController = ChewieController( videoPlayerController: videoPlayerController, autoPlay: widget.autoPlay, aspectRatio: 16 / 9, autoInitialize: true, errorBuilder: (context, errorMessage) { return Center( child: Text( errorMessage, style: const TextStyle(color: Colors.white), ), ); }, customControls: const MaterialControls(), materialProgressColors: ChewieProgressColors( playedColor: Colors.lightBlue, handleColor: Colors.white, bufferedColor: Colors.white.withOpacity(0.5), backgroundColor: Colors.grey.withOpacity(.5), ), // 添加全屏占位组件,包含手势检测 fullScreenPlaceholder: Builder( builder: (context) { return GestureDetector( onPanUpdate: (details) { if (details.delta.dy < -5) { // 先退出全屏,再跳转页面 Navigator.of(context).pop(); Navigator.of(context).push( MaterialPageRoute<void>( builder: (BuildContext context) => MainScreen(1), ), ); } }, child: Chewie(controller: chewieController), ); }, ), );
方法2:自定义Controls嵌入手势
默认的MaterialControls可能会拦截部分手势,我们可以继承它并添加全局手势:
- 创建自定义Controls类:
class CustomMaterialControls extends MaterialControls { final VoidCallback onSwipeDown; CustomMaterialControls({required this.onSwipeDown}); @override Widget build(BuildContext context, ChewieController controller) { return GestureDetector( onPanUpdate: (details) { if (controller.isFullScreen && details.delta.dy < -5) { onSwipeDown(); } }, // 保留原有的Controls功能 child: super.build(context, controller), ); } }
- 在ChewieController中使用自定义Controls:
chewieController = ChewieController( // 其他参数保持不变 customControls: CustomMaterialControls( onSwipeDown: () { chewieController.exitFullScreen(); Navigator.of(context).push( MaterialPageRoute<void>( builder: (BuildContext context) => MainScreen(1), ), ); }, ), );
方法3:通过Overlay添加全局手势监听
监听Chewie的全屏状态变化,进入全屏时在Overlay层添加透明的手势检测器:
class _ChewieVideoWidgetState extends State<ChewieVideoWidget> { late ChewieController chewieController; late VideoPlayerController videoPlayerController; bool _isPlaying = false; OverlayEntry? _fullScreenGestureOverlay; // 新增OverlayEntry @override void initState() { super.initState(); videoPlayerController = VideoPlayerController.asset(widget.asset); chewieController = ChewieController( // 原有参数保持不变 ); // 添加全屏状态监听 chewieController.addListener(_onFullScreenChanged); // 原有延迟代码... } // 处理全屏状态变化 void _onFullScreenChanged() { if (chewieController.isFullScreen) { _fullScreenGestureOverlay = OverlayEntry( builder: (context) => GestureDetector( onPanUpdate: (details) { if (details.delta.dy < -5) { chewieController.exitFullScreen(); Navigator.of(context).push( MaterialPageRoute<void>( builder: (BuildContext context) => MainScreen(1), ), ); _fullScreenGestureOverlay?.remove(); _fullScreenGestureOverlay = null; } }, child: Container(color: Colors.transparent), ), ); Overlay.of(context).insert(_fullScreenGestureOverlay!); } else { _fullScreenGestureOverlay?.remove(); _fullScreenGestureOverlay = null; } } @override void dispose() { chewieController.removeListener(_onFullScreenChanged); // 移除监听 _fullScreenGestureOverlay?.remove(); // 清理Overlay // 原有dispose代码... super.dispose(); } // 原有build方法保持不变... }
内容的提问来源于stack exchange,提问作者Justin Rudolph
相关产品推荐
相关产品推荐

