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

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,最后只有最后一个视频的实例生效。

修复步骤

  1. 给IframeScreen添加全局唯一的前缀参数,确保每个实例的注册键不重复
  2. 修改注册键和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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 20:14:51