Flutter中如何在GridView展示视频并实现点击播放(类似相册)
实现视频相册:FilePicker获取视频+GridView展示+点击播放
下面是实现该功能的完整步骤和代码示例,涵盖从视频获取到展示、播放的全流程:
1. 添加必要依赖
在pubspec.yaml中添加以下依赖,分别用于文件选择、视频播放和简化播放器UI:
dependencies: flutter: sdk: flutter file_picker: ^5.3.2 # 版本号可按需更新 video_player: ^2.6.1 chewie: ^1.3.4 # 可选,封装了播放控制栏,大幅简化开发
执行flutter pub get完成依赖安装。
2. 配置权限
Android
在android/app/src/main/AndroidManifest.xml中添加读写权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
iOS
在ios/Runner/Info.plist中添加相册访问权限描述:
<key>NSPhotoLibraryUsageDescription</key> <string>需要访问相册以选择视频</string>
3. 核心代码实现
主页面:视频选择与GridView展示
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:file_picker/file_picker.dart'; import 'package:video_player/video_player.dart'; import 'video_player_page.dart'; class VideoGalleryPage extends StatefulWidget { const VideoGalleryPage({super.key}); @override State<VideoGalleryPage> createState() => _VideoGalleryPageState(); } class _VideoGalleryPageState extends State<VideoGalleryPage> { List<String> _videoPaths = []; Map<String, VideoPlayerController> _thumbnailControllers = {}; // 批量选择视频文件 Future<void> _pickVideos() async { final result = await FilePicker.platform.pickFiles( type: FileType.video, allowMultiple: true, ); if (result != null) { setState(() { _videoPaths = result.files.map((file) => file.path!).toList(); }); // 预加载缩略图控制器 for (var path in _videoPaths) { final controller = VideoPlayerController.file(File(path)); await controller.initialize(); setState(() { _thumbnailControllers[path] = controller; }); } } } @override void dispose() { // 释放所有缩略图控制器,避免内存泄漏 for (var controller in _thumbnailControllers.values) { controller.dispose(); } super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('视频相册'), actions: [ IconButton( icon: const Icon(Icons.add), onPressed: _pickVideos, ), ], ), body: _videoPaths.isEmpty ? const Center(child: Text('点击右上角添加视频')) : GridView.builder( padding: const EdgeInsets.all(8), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, crossAxisSpacing: 8, mainAxisSpacing: 8, ), itemCount: _videoPaths.length, itemBuilder: (context, index) { final path = _videoPaths[index]; final controller = _thumbnailControllers[path]; return GestureDetector( onTap: () { // 跳转到单独的播放页面 Navigator.push( context, MaterialPageRoute( builder: (context) => VideoPlayerPage(videoPath: path), ), ); }, child: Stack( fit: StackFit.expand, children: [ // 用视频第一帧作为缩略图 controller != null ? VideoPlayer(controller) : const Center(child: CircularProgressIndicator()), // 叠加播放图标提示可点击 const Center( child: Icon( Icons.play_circle, color: Colors.white, size: 40, ), ), ], ), ); }, ), ); } }
视频播放页面
创建video_player_page.dart,借助Chewie实现带完整控制栏的播放功能:
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; import 'package:chewie/chewie.dart'; class VideoPlayerPage extends StatefulWidget { final String videoPath; const VideoPlayerPage({super.key, required this.videoPath}); @override State<VideoPlayerPage> createState() => _VideoPlayerPageState(); } class _VideoPlayerPageState extends State<VideoPlayerPage> { late VideoPlayerController _videoController; late ChewieController _chewieController; @override void initState() { super.initState(); _initializePlayer(); } Future<void> _initializePlayer() async { _videoController = VideoPlayerController.file(File(widget.videoPath)); await _videoController.initialize(); _chewieController = ChewieController( videoPlayerController: _videoController, autoPlay: true, looping: false, materialProgressColors: ChewieProgressColors( playedColor: Colors.blue, handleColor: Colors.blueAccent, ), ); setState(() {}); } @override void dispose() { _videoController.dispose(); _chewieController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('播放视频')), body: _videoController.value.isInitialized ? Chewie(controller: _chewieController) : const Center(child: CircularProgressIndicator()), ); } }
关键细节说明
- 缩略图生成:直接利用
VideoPlayerController加载视频并初始化,通过VideoPlayer组件展示第一帧,无需额外依赖,高效简洁。 - 内存管理:页面销毁时必须释放所有
VideoPlayerController,防止内存泄漏。 - 播放体验:Chewie封装了播放/暂停、进度拖动、全屏切换等常用功能,无需手动实现复杂控制逻辑。
内容的提问来源于stack exchange,提问作者Vishwa Teja Averager
相关产品推荐
相关产品推荐

