如何通过TextFormField输入链接动态展示视频?
问题
我们有TextFormField和ElevatedButton组件,要求用户输入MP4格式的视频URL,点击按钮后在组件下方展示从该URL爬取的视频。打算用video_player包,但示例代码要求在initState(或GetX的onInit)中设置初始URL,请问怎么实现URL动态化,且仅在输入URL后才展示视频?
现有代码
控制器代码
class CyberDropController extends GetxController with StateMixin<List> { final dataCyberDrop = DataCyberDrop(); late VideoPlayerController videoController; var url = ''.obs; @override void onInit() { super.onInit(); playVideo(url.value); change(null, status: RxStatus.empty()); } Future<void> playVideo(String url) async { videoController = VideoPlayerController.network(url); await videoController.initialize(); await videoController.setLooping(true); await videoController.play(); update(); } void fetch({String? link}) async { change(null, status: RxStatus.loading()); try { var data = await dataCyberDrop.scraperCyberDrop(link: link); change(data, status: RxStatus.success()); } catch (e) { change(null, status: RxStatus.error(e.toString())); } } }
视图代码
controller.obx( (state) => Column( children: state! .map( (e) => e!.toString().contains('.mp4') ? AspectRatio( aspectRatio: controller .videoController.value.aspectRatio, child: VideoPlayer(controller.videoController), ) : Image.network(e), ) .toList(), )
解决方案
1. 修复控制器初始化逻辑,避免空URL报错
原代码在onInit里直接调用playVideo传入空字符串,会导致VideoPlayerController初始化失败。我们需要:
- 把
videoController改为可空类型,避免late变量未初始化的风险 - 移除
onInit中的playVideo调用,只在用户输入有效URL后再初始化控制器
修改后的控制器变量定义:
VideoPlayerController? videoController;
2. 优化playVideo方法,处理动态切换与资源释放
动态切换URL时,必须先释放旧的控制器,否则会造成内存泄漏。同时增加URL有效性判断:
Future<void> playVideo(String url) async { // 先释放旧的控制器 if (videoController != null) { await videoController!.dispose(); } if (url.isEmpty || !url.endsWith('.mp4')) { change(null, status: RxStatus.error('请输入有效的MP4视频链接')); return; } try { videoController = VideoPlayerController.network(url); await videoController!.initialize(); await videoController!.setLooping(true); await videoController!.play(); update(); // 更新视图 } catch (e) { change(null, status: RxStatus.error('视频加载失败: ${e.toString()}')); } }
3. 绑定输入框与按钮逻辑
在视图中添加TextFormField和ElevatedButton,将输入内容绑定到控制器的url变量,点击按钮时触发视频加载:
// 输入框部分 Obx( () => TextFormField( decoration: const InputDecoration(hintText: '输入MP4视频URL'), onChanged: (value) => controller.url.value = value, controller: TextEditingController(text: controller.url.value), ), ), // 按钮部分 ElevatedButton( onPressed: () { // 如果需要先爬取链接,调用fetch后再处理返回的MP4地址 // controller.fetch(link: controller.url.value); // 直接加载输入的URL则调用playVideo controller.playVideo(controller.url.value); }, child: const Text('加载视频'), ),
4. 条件渲染视频组件
只有当videoController存在且已初始化时,才展示视频播放器,避免空指针错误:
controller.obx( (state) => Column( children: state! .map( (e) { if (e!.toString().contains('.mp4')) { // 若为爬取到的MP4链接,可在fetch成功后调用playVideo加载对应链接 // 单视频场景下直接判断当前videoController状态 return controller.videoController != null && controller.videoController!.value.isInitialized ? AspectRatio( aspectRatio: controller.videoController!.value.aspectRatio, child: VideoPlayer(controller.videoController!), ) : const SizedBox.shrink(); } else { return Image.network(e); } }, ) .toList(), ), ),
5. 资源清理(可选但重要)
在控制器的onClose方法中释放视频控制器,避免内存泄漏:
@override void onClose() { videoController?.dispose(); super.onClose(); }
多视频场景补充(如果爬取返回多个MP4链接)
如果fetch方法返回的列表中有多个MP4链接,需要为每个视频创建独立的控制器。可以把videoController改为Map<String, VideoPlayerController?>来存储每个链接对应的控制器,在遍历state时初始化对应链接的控制器。
内容的提问来源于stack exchange,提问作者nghkh
相关产品推荐
相关产品推荐

