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

Flutter如何传递拍摄的图片/视频到下一页展示及实现多素材网格布局

实现方案

一、同页展示所有拍摄视频

你原本的代码只存储了单个视频文件,要实现多视频网格展示(和你示例图效果一致),需要做以下修改:

  • 将存储单个视频的变量改为List<File>类型,用于保存所有拍摄完成的视频文件
  • 展示区域替换为GridView网格布局,设置每行展示的个数即可实现和示例一致的排版
  • 每次拍摄完成后将新视频存入列表即可自动刷新展示

二、将视频传递到下一页

新手最容易上手的是构造函数传参的方式,直接把存储视频路径的列表作为参数传给下一个页面的构造函数即可,不需要额外依赖。如果需要跨多个页面传递,也可以选择Provider状态管理、shared_preferences本地存储等方案。

修改后的完整代码

import 'dart:io';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart' as syspaths;
import 'package:flutter/material.dart';

// 拍摄页面
class VideoRecord02 extends StatefulWidget {
  final Function? onSelectVideo;
  const VideoRecord02({Key? key, this.onSelectVideo}) : super(key: key);

  @override
  _VideoRecord02State createState() => _VideoRecord02State();
}

class _VideoRecord02State extends State<VideoRecord02> {
  String dropdownValue = 'Bedroom';
  // 改为列表存储所有拍摄的视频
  List<File> storedVideos = [];

  Future<void> _takeVideo() async {
    final picker = ImagePicker();
    final videoFile = await picker.pickVideo(
      source: ImageSource.camera,
      preferredCameraDevice: CameraDevice.rear,
      maxDuration: const Duration(seconds: 25),
    );
    if (videoFile == null) {
      return;
    }
    final rlyvideoFile = File(videoFile.path);
    final appDir = await syspaths.getApplicationDocumentsDirectory();
    final fileName = path.basename(rlyvideoFile.path);
    final savedVideo = await rlyvideoFile.copy('${appDir.path}/$fileName');
    // 新视频加入列表
    setState(() {
      storedVideos.add(savedVideo);
    });
    widget.onSelectVideo?.call(savedVideo);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.white,
        body: Center(
          child: ListView(
            shrinkWrap: true,
            children: [
              Column(
                children: [
                  // 视频展示区域改为网格布局,和示例图一致一行3个
                  storedVideos.isNotEmpty ? 
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: GridView.count(
                      shrinkWrap: true,
                      physics: const NeverScrollableScrollPhysics(),
                      crossAxisCount: 3,
                      crossAxisSpacing: 4,
                      mainAxisSpacing: 4,
                      childAspectRatio: 1.5/1,
                      children: storedVideos.map((video) {
                        return Container(
                          decoration: BoxDecoration(
                            border: Border.all(width: 0.5, color: Colors.grey),
                          ),
                          child: VideoWidget(video),
                        );
                      }).toList(),
                    ),
                  ) : Container(
                    width: 150,
                    height: 100,
                    decoration: BoxDecoration(
                      border: Border.all(width: 0.5, color: Colors.grey),
                    ),
                    child: const Text(
                      'No Video Taken',
                      textAlign: TextAlign.center,
                    ),
                    alignment: Alignment.center,
                  ),
                  Align(
                    alignment: Alignment.center,
                    child: Column(
                      children: [
                        IconButton(
                          icon: const Icon(Icons.play_circle_fill),
                          color: Colors.red,
                          iconSize: 100.0,
                          onPressed: _takeVideo,
                        ),
                      ],
                    ),
                  ),
                  const Text(
                    'Click to start',
                    style: TextStyle(
                      fontSize: 25.0,
                      color: Colors.red,
                      fontWeight: FontWeight.w300,
                    ),
                  ),
                  Container(
                    margin: const EdgeInsets.fromLTRB(125, 0, 125, 0),
                    height: 50,
                    padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
                    child: TextButton(
                      child: const Text(
                        '< Back',
                        style: TextStyle(fontSize: 17, color: Colors.black),
                      ),
                      onPressed: () {
                        // 跳转到下一页时将视频列表作为参数传入
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (context) => VideoDisplayPage(videoList: storedVideos),
                          ),
                        );
                      },
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

// 接收视频的下一页示例
class VideoDisplayPage extends StatelessWidget {
  // 构造函数接收视频列表
  final List<File> videoList;
  const VideoDisplayPage({Key? key, required this.videoList}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("已拍摄视频")),
      body: GridView.count(
        padding: const EdgeInsets.all(8),
        crossAxisCount: 3,
        crossAxisSpacing: 4,
        mainAxisSpacing: 4,
        childAspectRatio: 1.5/1,
        children: videoList.map((video) {
          return Container(
            decoration: BoxDecoration(
              border: Border.all(width: 0.5, color: Colors.grey),
            ),
            child: VideoWidget(video),
          );
        }).toList(),
      ),
    );
  }
}

// 你原有VideoWidget保持不变即可
class VideoWidget extends StatelessWidget {
  final File videoFile;
  const VideoWidget(this.videoFile, {Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 你的视频播放实现逻辑
    return const Center(child: Icon(Icons.video_library));
  }
}

优化建议

如果视频数量较多,建议使用video_thumbnail包生成视频缩略图代替直接加载完整视频组件,可以大幅提升页面流畅度。


内容的提问来源于stack exchange,提问作者Maahdi.Codes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 06:57:03