Flutter中Chewie实现竖屏全屏m3u8短视频的非源码修改方案咨询
解决方案:Chewie竖屏全屏播放.m3u8无留白问题
替代方案1:自定义Chewie的ControlsOverlay
Chewie支持传入自定义控件层,无需修改源码就能完全接管布局逻辑:
- 自定义一个继承
StatelessWidget的控件类,内部直接返回VideoPlayer组件,或按需添加播放控制按钮,布局上强制让视频占满屏幕。 - 示例代码:
class CustomVideoControls extends StatelessWidget { final ChewieController controller; const CustomVideoControls({super.key, required this.controller}); @override Widget build(BuildContext context) { return GestureDetector( onTap: () => controller.togglePlay(), child: SizedBox.expand( child: FittedBox( fit: BoxFit.cover, child: SizedBox( width: controller.videoPlayerController.value.size.width, height: controller.videoPlayerController.value.size.height, child: VideoPlayer(controller.videoPlayerController), ), ), ), ); } }
初始化Chewie时使用该自定义控件:
Chewie( controller: ChewieController( videoPlayerController: _videoPlayerController, customControls: CustomVideoControls(controller: chewieController), allowFullScreen: false, // 自行处理全屏逻辑,弃用Chewie自带功能 aspectRatio: MediaQuery.of(context).size.height / MediaQuery.of(context).size.width, ), )
替代方案2:改用better_player库
better_player原生支持HLS(.m3u8)格式,对竖屏全屏适配更友好,无需依赖Chewie:
- 初始化控制器时设置适配模式为
BoxFit.cover,强制占满竖屏:
BetterPlayerController _betterPlayerController = BetterPlayerController( BetterPlayerConfiguration( aspectRatio: MediaQuery.of(context).size.height / MediaQuery.of(context).size.width, fit: BoxFit.cover, fullScreenAspectRatio: MediaQuery.of(context).size.height / MediaQuery.of(context).size.width, autoPlay: true, ), );
加载.m3u8资源:
_betterPlayerController.setBetterPlayerDataSource( BetterPlayerDataSource( BetterPlayerDataSourceType.network, "你的.m3u8链接", ), );
使用BetterPlayer组件:
BetterPlayer(controller: _betterPlayerController)
替代方案3:封装独立的VideoPlayer组件
既然直接使用VideoPlayer能解决问题,可自行封装包含播放控制逻辑的组件,完全脱离Chewie的布局限制:
- 以
VideoPlayer为核心,外层用GestureDetector处理点击播放/暂停,布局上用SizedBox.expand配合FittedBox.cover确保无留白:
class VerticalVideoPlayer extends StatefulWidget { final String url; const VerticalVideoPlayer({super.key, required this.url}); @override State<VerticalVideoPlayer> createState() => _VerticalVideoPlayerState(); } class _VerticalVideoPlayerState extends State<VerticalVideoPlayer> { late VideoPlayerController _controller; late Future<void> _initializeVideoPlayerFuture; @override void initState() { super.initState(); // 需使用支持.m3u8的video_player分支,如video_player_hls _controller = VideoPlayerController.networkUrl(Uri.parse(widget.url)); _initializeVideoPlayerFuture = _controller.initialize(); _controller.play(); _controller.setLooping(true); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return FutureBuilder( future: _initializeVideoPlayerFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return GestureDetector( onTap: () { setState(() { _controller.value.isPlaying ? _controller.pause() : _controller.play(); }); }, child: SizedBox.expand( child: FittedBox( fit: BoxFit.cover, child: SizedBox( width: _controller.value.size.width, height: _controller.value.size.height, child: VideoPlayer(_controller), ), ), ), ); } else { return const Center(child: CircularProgressIndicator()); } }, ); } }
内容的提问来源于stack exchange,提问作者Sitam Sardar
相关产品推荐
相关产品推荐

