如何在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
相关产品推荐
相关产品推荐

