Flutter Web多YouTube视频渲染失败问题求助
Flutter Web多YouTube视频渲染失败问题
我用Flutter开发网站,单个YouTube视频页面渲染正常,但渲染多个视频时失败。排查发现仅一个嵌入视频被绑定到DOM解析器。我试过把不同视频链接放在独立组件里,还是只能渲染单个视频。下面是示例代码,assets[pageIndex]是传入的视频链接,由Iframe展示。求帮助,需要其他信息请说。提前致谢,排灯节快乐 :)
import 'dart:html'; import 'dart:ui_web' as ui; import 'package:flutter/material.dart'; class IframeScreen extends StatefulWidget { final List<String> urlDataList; IframeScreen(this.urlDataList, {Key? key}) : super(key: key); @override State<IframeScreen> createState() => _IframeScreenState(); } class _IframeScreenState extends State<IframeScreen> { late List<IFrameElement> _iframeElements; @override void initState() { super.initState(); _iframeElements = List.generate( widget.urlDataList.length, (index) { var iframeElement = IFrameElement() ..src = widget.urlDataList[index] ..style.border = 'none' ..allowFullscreen = true; // Enable JavaScript iframeElement.attributes['allow'] = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'; // Register the iframe element with a unique key using index ui.platformViewRegistry.registerViewFactory( 'iframeElement$index', (int viewId) => iframeElement, ); print('Registered iframeElement$index: ${iframeElement.src}'); return iframeElement; }, ); } @override Widget build(BuildContext context) { return Column( children: [ for (int index = 0; index < widget.urlDataList.length; index++) Expanded( child: Container( child: HtmlElementView( viewType: 'iframeElement$index', key: UniqueKey(), ), ), ), ], ); } } class YourWidget extends StatelessWidget { final List<String> assets; final List<String> title; YourWidget({required this.assets, required this.title}); @override Widget build(BuildContext context) { var screenSize = MediaQuery.of(context).size; return Scaffold( body: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ...Iterable<int>.generate(assets.length).map( (int pageIndex) => Column( children: [ SizedBox( height: screenSize.width / 6, width: screenSize.width / 3.8, child: InkWell( onTap: () { print(pageIndex); }, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(20.0), boxShadow: [ BoxShadow( offset: Offset(0, 10), blurRadius: 20, spreadRadius: 5, color: Colors.grey.withOpacity(0.3), ) ], ), child: IframeScreen([assets[pageIndex]]), ), ), ), Padding( padding: EdgeInsets.only( top: screenSize.height / 70, ), child: Text( title[pageIndex], style: TextStyle( fontSize: 20, color: Colors.orangeAccent, fontFamily: 'Montserrat', fontWeight: FontWeight.w500, ), ), ), ], ), ), ], ), ); } } void main() { runApp( MaterialApp( home: YourWidget( assets: ['your_video_url_1', 'your_video_url_2'], title: ['Title 1', 'Title 2'], ), ), ); }
问题原因及解决方法
问题根源
ui.platformViewRegistry.registerViewFactory的注册键是全局唯一的,重复注册会覆盖之前的实例。你现在每个IframeScreen实例传入的urlDataList长度都是1,所以内部循环的index始终是0,导致所有实例都注册了同一个键iframeElement0,最后只有最后一个视频的实例生效。
修复步骤
- 给
IframeScreen添加全局唯一的前缀参数,确保每个实例的注册键不重复 - 修改注册键和
HtmlElementView的viewType,使用前缀+内部索引的组合
修改后的IframeScreen代码
class IframeScreen extends StatefulWidget { final List<String> urlDataList; final String uniquePrefix; // 新增全局唯一前缀参数 const IframeScreen(this.urlDataList, {required this.uniquePrefix, Key? key}) : super(key: key); @override State<IframeScreen> createState() => _IframeScreenState(); } class _IframeScreenState extends State<IframeScreen> { late List<IFrameElement> _iframeElements; @override void initState() { super.initState(); _iframeElements = List.generate( widget.urlDataList.length, (index) { var iframeElement = IFrameElement() ..src = widget.urlDataList[index] ..style.border = 'none' ..allowFullscreen = true; iframeElement.attributes['allow'] = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'; // 用唯一前缀+内部索引生成全局唯一的注册键 final viewKey = '${widget.uniquePrefix}_iframeElement$index'; ui.platformViewRegistry.registerViewFactory( viewKey, (int viewId) => iframeElement, ); print('Registered $viewKey: ${iframeElement.src}'); return iframeElement; }, ); } @override Widget build(BuildContext context) { return Column( children: [ for (int index = 0; index < widget.urlDataList.length; index++) Expanded( child: HtmlElementView( viewType: '${widget.uniquePrefix}_iframeElement$index', key: UniqueKey(), ), ), ], ); } }
修改YourWidget中调用IframeScreen的代码
把pageIndex作为唯一前缀传入,确保每个实例的注册键不重复:
child: IframeScreen( [assets[pageIndex]], uniquePrefix: 'video_$pageIndex', ),
这样每个视频的注册键会变成video_0_iframeElement0、video_1_iframeElement0,全局唯一,不会互相覆盖,多个视频就能正常渲染了。
内容的提问来源于stack exchange,提问作者Kartikeya Tiwari
相关产品推荐
相关产品推荐

