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

Flutter中如何从相册选取多个视频并展示

实现Flutter相册多选视频并展示的完整方案

我来帮你搞定Flutter里多选相册视频并展示的需求,这是一套经过验证的完整方案:

1. 引入必要的依赖

先在pubspec.yaml里添加三个关键依赖:

  • image_picker:官方维护的媒体选择器,支持多选指定类型的媒体
  • video_player:用于播放和展示选中的视频
  • permission_handler:处理权限申请,确保能正常访问相册
dependencies:
  flutter:
    sdk: flutter
  image_picker: ^1.0.7
  video_player: ^2.8.0
  permission_handler: ^10.2.0

添加后执行flutter pub get安装依赖。

2. 配置平台权限

Android配置

打开android/app/src/main/AndroidManifest.xml,添加对应权限:

<!-- Android 13+ 专属视频访问权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- Android 12及以下 外部存储访问权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

iOS配置

打开ios/Runner/Info.plist,添加权限说明(必须填写,否则App会被拒):

<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问您的相册以选择视频</string>

3. 完整功能实现代码

下面是包含权限申请、视频多选、视频展示的可直接运行代码:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:video_player/video_player.dart';

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

  @override
  State<MultiVideoPickerScreen> createState() => _MultiVideoPickerScreenState();
}

class _MultiVideoPickerScreenState extends State<MultiVideoPickerScreen> {
  final ImagePicker _picker = ImagePicker();
  List<XFile> _selectedVideos = [];
  List<VideoPlayerController?> _videoControllers = [];

  // 申请相册权限
  Future<bool> _requestGalleryPermission() async {
    final status = await Permission.photos.request();
    return status.isGranted;
  }

  // 选择多个视频
  Future<void> _pickVideos() async {
    final hasPermission = await _requestGalleryPermission();
    if (!hasPermission) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('需要授予相册权限才能选择视频')),
      );
      return;
    }

    final List<XFile>? pickedVideos = await _picker.pickMedia(
      mediaType: MediaType.video,
      allowMultiple: true,
    );

    if (pickedVideos != null && pickedVideos.isNotEmpty) {
      setState(() {
        _selectedVideos = pickedVideos;
      });
      _initVideoControllers();
    }
  }

  // 初始化所有选中视频的播放控制器
  void _initVideoControllers() {
    _videoControllers = List.generate(
      _selectedVideos.length,
      (index) => VideoPlayerController.file(
        File(_selectedVideos[index].path),
      )..initialize().then((_) {
          setState(() {});
        }),
    );
  }

  // 页面销毁时释放控制器,避免内存泄漏
  @override
  void dispose() {
    for (var controller in _videoControllers) {
      controller?.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('多选视频展示')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16),
            child: ElevatedButton(
              onPressed: _pickVideos,
              child: const Text('从相册选择视频'),
            ),
          ),
          Expanded(
            child: _selectedVideos.isEmpty
                ? const Center(child: Text('暂无选中的视频'))
                : GridView.builder(
                    padding: const EdgeInsets.symmetric(horizontal: 16),
                    gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                      crossAxisCount: 2,
                      crossAxisSpacing: 12,
                      mainAxisSpacing: 12,
                    ),
                    itemCount: _selectedVideos.length,
                    itemBuilder: (context, index) {
                      final controller = _videoControllers[index];
                      return controller != null && controller.value.isInitialized
                          ? GestureDetector(
                              onTap: () {
                                setState(() {
                                  controller.value.isPlaying
                                      ? controller.pause()
                                      : controller.play();
                                });
                              },
                              child: Stack(
                                alignment: Alignment.center,
                                children: [
                                  VideoPlayer(controller),
                                  if (!controller.value.isPlaying)
                                    const Icon(
                                      Icons.play_circle_fill,
                                      size: 48,
                                      color: Colors.white,
                                    ),
                                ],
                              ),
                            )
                          : const Center(child: CircularProgressIndicator());
                    },
                  ),
          ),
        ],
      ),
    );
  }
}

// 测试入口
void main() => runApp(const MaterialApp(home: MultiVideoPickerScreen()));

4. 关键注意事项

  • 权限前置检查:必须先申请权限再打开相册,否则会直接被系统拒绝访问
  • 控制器内存管理:每个视频对应一个VideoPlayerController,一定要在页面销毁时释放,避免内存泄漏
  • 性能优化:如果需要支持大量视频选中,建议做懒加载控制器或者限制选中数量,防止内存占用过高
  • 平台适配:Android 13+和旧版本的权限配置不同,一定要按步骤配置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 16:07:40