使用youtube_player_iframe加载多视频时出现错误问题
多Youtube Player Iframe组件同时显示时部分加载失败的解决方案
当页面可视区域内同时渲染多个Youtube播放器组件时,部分播放器会报错无法加载视频——移动端场景下这个问题尤为明显,但单个播放器或播放器全屏时均能正常加载。以下结合youtube_player_iframe包的特性,给出针对性解决方法:
问题代码参考
class YoutubeViewer extends Stateful Widget { final String videoID; const YoutubeViewer(this.videoID, {super.key}); @override _YoutubeViewerState createState() => _YoutubeViewerState(); } class _YoutubeViewerState extends State<YoutubeViewer> with AutomaticKeepAliveClientMixin { late final YoutubePlayerController controller; bool isPlaying = false; @override bool get wantKeepAlive => true; @override void initState() { super.initState(); controller = YoutubePlayerController.fromVideoId( params: const YoutubePlayerParams( enableCaption: false, showVideoAnnotations: false, playsInline: false, showFullscreenButton: true, ), videoId: widget.videoID, )..listen((event) { final playerState = event.playerState; if (playerState == PlayerState.playing) { setState(() { isPlaying = true; }); } else if (playerState == PlayerState.ended || playerState == PlayerState.paused || playerState == PlayerState.unknown) { setState(() { isPlaying = false; }); } }); } @override void dispose() { controller.close(); super.dispose(); } @override Widget build(BuildContext context) { super.build(context); final player = YoutubePlayer( controller: controller, key: ValueKey(widget.videoID), gestureRecognizers: isPlaying ? null : <Factory<OneSequenceGestureRecognizer>>{}, ); return Padding( padding: const EdgeInsets.symmetric(horizontal: Dimensions.spacingLong), child: Stack( children: [ player, Positioned.fill( child: PointerInterceptor( intercepting: !isPlaying, child: MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( onTap: () async => controller.playVideo(), ), ), ), ), ], ), ); } }
具体解决方法
1. 修改内联播放参数
移动端对Youtube非内联播放有严格限制,将playsInline设为true,避免触发平台级的播放限制:
params: const YoutubePlayerParams( enableCaption: false, showVideoAnnotations: false, playsInline: true, // 改为true showFullscreenButton: true, ),
2. 延迟初始化可视区域外的播放器
Youtube对同时加载的播放器数量有限制(通常最多6个),通过监听组件可见性,仅在组件进入视口时初始化控制器,离开时销毁:
- 引入
visibility_detector包实现可见性监听 - 调整控制器初始化逻辑,仅在组件可见时创建实例
修改后的核心代码:
class _YoutubeViewerState extends State<YoutubeViewer> with AutomaticKeepAliveClientMixin { YoutubePlayerController? controller; bool isPlaying = false; bool isVisible = false; @override bool get wantKeepAlive => true; void _initController() { controller = YoutubePlayerController.fromVideoId( params: const YoutubePlayerParams( enableCaption: false, showVideoAnnotations: false, playsInline: true, showFullscreenButton: true, ), videoId: widget.videoID, )..listen((event) { final playerState = event.playerState; if (playerState == PlayerState.playing) { setState(() => isPlaying = true); } else if ([PlayerState.ended, PlayerState.paused, PlayerState.unknown].contains(playerState)) { setState(() => isPlaying = false); } }); } void _disposeController() { controller?.close(); controller = null; } @override void dispose() { _disposeController(); super.dispose(); } @override Widget build(BuildContext context) { super.build(context); return VisibilityDetector( key: ValueKey(widget.videoID), onVisibilityChanged: (info) { final visible = info.visibleFraction > 0.5; if (visible != isVisible) { setState(() { isVisible = visible; isVisible ? _initController() : _disposeController(); }); } }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: Dimensions.spacingLong), child: Stack( children: [ controller != null ? YoutubePlayer( controller: controller!, key: ValueKey(widget.videoID), gestureRecognizers: isPlaying ? null : <Factory<OneSequenceGestureRecognizer>>{}, ) : Container( color: Colors.black, child: const Center(child: CircularProgressIndicator()), ), Positioned.fill( child: PointerInterceptor( intercepting: !isPlaying, child: MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( onTap: () async => controller?.playVideo(), ), ), ), ), ], ), ), ); } }
3. 限制同时播放的视频数量
Youtube不允许同时播放多个视频,在父组件中维护播放状态,当某个视频开始播放时,暂停其他所有播放器的播放状态,避免冲突。
4. 更新包版本
确保使用最新版的youtube_player_iframe,旧版本可能存在多实例加载的已知bug,更新后可修复部分兼容性问题。
内容的提问来源于stack exchange,提问作者M14
相关产品推荐
相关产品推荐

