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

如何在Flutter应用的YouTube播放器iframe全屏模式添加文字水印

YouTube播放器iframe全屏添加文字水印的解决方案

针对Flutter中YouTube播放器iframe全屏时水印失效的问题,可通过以下几种方式解决:

一、自定义全屏逻辑(复用Stack布局)

默认播放器全屏会脱离Flutter Widget树,因此可以禁用原生全屏按钮,自行实现全屏切换:

  • 初始化播放器时关闭原生全屏功能:通过YoutubePlayerFlags设置fullScreenButton: false,避免触发原生全屏。
  • 手动控制全屏状态:结合SystemChrome切换系统UI(隐藏状态栏/导航栏)和屏幕方向,将包含播放器和水印的Stack布局扩展至全屏。
  • 示例代码:
import 'package:flutter/services.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';

class VideoPlayerPage extends StatefulWidget {
  const VideoPlayerPage({super.key});

  @override
  State<VideoPlayerPage> createState() => _VideoPlayerPageState();
}

class _VideoPlayerPageState extends State<VideoPlayerPage> {
  final _controller = YoutubePlayerController(
    initialVideoId: 'your_video_id',
    flags: const YoutubePlayerFlags(
      autoPlay: false,
      fullScreenButton: false, // 禁用原生全屏按钮
    ),
  );
  bool _isFullScreen = false;

  void _toggleFullScreen() {
    setState(() => _isFullScreen = !_isFullScreen);
    if (_isFullScreen) {
      SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.landscapeLeft,
        DeviceOrientation.landscapeRight,
      ]);
    } else {
      SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
      SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _isFullScreen
          ? Stack(
              fit: StackFit.expand,
              children: [
                YoutubePlayer(controller: _controller),
                // 水印
                const Positioned(
                  bottom: 20,
                  right: 20,
                  child: Text(
                    '专属水印',
                    style: TextStyle(color: Colors.white, fontSize: 16),
                  ),
                ),
                // 自定义退出全屏按钮
                Positioned(
                  top: 40,
                  left: 20,
                  child: IconButton(
                    icon: const Icon(Icons.fullscreen_exit, color: Colors.white),
                    onPressed: _toggleFullScreen,
                  ),
                ),
              ],
            )
          : Stack(
              children: [
                YoutubePlayer(controller: _controller),
                const Positioned(
                  bottom: 10,
                  right: 10,
                  child: Text('专属水印', style: TextStyle(color: Colors.white)),
                ),
                // 自定义进入全屏按钮
                Positioned(
                  top: 10,
                  right: 10,
                  child: IconButton(
                    icon: const Icon(Icons.fullscreen, color: Colors.white),
                    onPressed: _toggleFullScreen,
                  ),
                ),
              ],
            ),
    );
  }
}

二、通过iframe注入JS/CSS添加水印

利用播放器的WebViewController注入自定义样式,让水印直接叠加在视频DOM上,原生全屏时也能生效:

  • 在播放器就绪后执行JS代码,创建水印元素并添加到视频容器中:
@override
void initState() {
  super.initState();
  _controller.onReady.listen(() {
    _controller.webViewController?.runJavascript('''
      const watermark = document.createElement('div');
      watermark.textContent = '专属水印';
      watermark.style.cssText = `
        position: fixed;
        bottom: 20px;
        right: 20px;
        color: white;
        font-size: 16px;
        z-index: 9999;
        pointer-events: none;
        text-shadow: 1px 1px 2px rgba(0,0,0,0.8);
      `;
      document.querySelector('.html5-video-container')?.appendChild(watermark);
    ''');
  });
}
  • 注意:该方案依赖YouTube播放器的DOM结构,若平台更新DOM可能需要调整选择器。

三、使用Overlay全局叠加水印

通过Flutter的Overlay组件添加全局水印,无论页面是否全屏,水印都会悬浮在所有内容上方:

  • 在页面初始化时插入OverlayEntry,页面销毁时移除:
late OverlayEntry _watermarkOverlay;

@override
void initState() {
  super.initState();
  _watermarkOverlay = OverlayEntry(
    builder: (context) => const Positioned(
      bottom: 20,
      right: 20,
      child: Text(
        '专属水印',
        style: TextStyle(color: Colors.white, fontSize: 16, shadows: [
          Shadow(color: Colors.black, blurRadius: 2)
        ]),
      ),
    ),
  );
  WidgetsBinding.instance.addPostFrameCallback((_) {
    Overlay.of(context).insert(_watermarkOverlay);
  });
}

@override
void dispose() {
  _watermarkOverlay.remove();
  super.dispose();
}
  • 此方案无需修改播放器逻辑,但要注意在页面销毁时及时移除OverlayEntry,避免内存泄漏。

内容的提问来源于stack exchange,提问作者slackgate

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 01:07:39