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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 13:15:18