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

如何在Flutter中使用camera_awesome包设置30秒录像时长限制

如何在camera_awesome中设置30秒视频录制时长限制并自动停止

我在Flutter项目中使用camera_awesome包实现照片与视频拍摄功能,希望为视频录制设置30秒时长限制,使录制到达时间后自动停止。目前我的实现中缺少该功能,恳请指导如何实现。以下是我的现有代码:

import 'dart:io';
import 'package:camerawesome/camerawesome_plugin.dart';
import 'package:camerawesome/pigeon.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
import 'package:tymelyne/AddPosts/MediaBank/MainMediaBankScreen.dart';
import 'package:tymelyne/AddPosts/MediaBank/MediaBankFullScreen.dart';
import 'package:tymelyne/Controllers/AuthDBController.dart';
import 'package:tymelyne/Universal/Widgets/UniversalWidgets.dart';
import '../Universal/Controllers/PersistController.dart';

// Instances
final _universalWidgets = UniversalWidgets();
final _persistControllerUNI = Get.find<PersistControllerUNI>();

//
class MyCameraAwesome extends StatelessWidget {
  const MyCameraAwesome({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CameraAwesomeBuilder.awesome(
        // Enable the volume buttons to take pictures or record videos
        enablePhysicalButton: true,

        //
        progressIndicator: Center(
          child: _universalWidgets.customProgressIndicator(),
        ),

        //
        availableFilters: awesomePresetFiltersList,

        //
        saveConfig: SaveConfig.photoAndVideo(
          initialCaptureMode: CaptureMode.photo,
          mirrorFrontCamera: true,

          photoPathBuilder: (sensors) async {
            final Directory extDir = await getApplicationDocumentsDirectory();
            final testDir = await Directory(
              '${extDir.path}/xyzapp',
            ).create(recursive: true);

            //
            if (sensors.length == 1) {
              final String filePath =
                  '${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.jpg';

              //
              _persistControllerUNI.updateAndPersistMediaBank(
                filePath: filePath,
                fileType: 'image',
              );

              return SingleCaptureRequest(filePath, sensors.first);
            } else {
              // Separate pictures taken with front and back camera
              return MultipleCaptureRequest(
                {
                  for (final sensor in sensors)
                    sensor:
                        '${testDir.path}/${sensor.position == SensorPosition.front ? 'front_' : "back_"}${DateTime.now().millisecondsSinceEpoch}.jpg',
                },
              );
            }
          },

          //
          videoPathBuilder: (sensors) async {
            final Directory extDir = await getApplicationDocumentsDirectory();
            final testDir = await Directory(
              '${extDir.path}/xyzapp',
            ).create(recursive: true);
            if (sensors.length == 1) {
              final String filePath =
                  '${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.mp4';

              //
              _persistControllerUNI.updateAndPersistMediaBank(
                filePath: filePath,
                fileType: 'video',
              );
              return SingleCaptureRequest(filePath, sensors.first);
            } else {
              // Separate pictures taken with front and back camera
              return MultipleCaptureRequest(
                {
                  for (final sensor in sensors)
                    sensor:
                        '${testDir.path}/${sensor.position == SensorPosition.front ? 'front_' : "back_"}${DateTime.now().millisecondsSinceEpoch}.jpg',
                },
              );
            }
          },

          videoOptions: VideoOptions(
            enableAudio: true,
            quality: VideoRecordingQuality.highest,
          ),

          exifPreferences: ExifPreferences(
            saveGPSLocation: false,
          ),
        ),

        //
        sensorConfig: SensorConfig.single(
          sensor: Sensor.position(SensorPosition.back),
          flashMode: FlashMode.none,
          aspectRatio: CameraAspectRatios.ratio_16_9,
          zoom: 0.0,
        ),

        //
        onMediaTap: (mediaCapture) {
          //
          mediaCapture.captureRequest.when(
            single: (single) async {
              if (single.file != null) {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const MainMediaBankScreen(),
                  ),
                );

                //
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const MediaBankFullScreen(
                      initialPageIndex: 0,
                    ),
                  ),
                );
              }
            },
          );

          //
          _persistControllerUNI.updateIsLandscapeModeMediaBank();
        },

        //
        topActionsBuilder: (state) {
          return AwesomeTopActions(
            state: state,
            padding: const EdgeInsets.only(
              left: 10,
              right: 10,
              top: 15,
            ),
            children: [
              //
              IconButton(
                onPressed: () => Navigator.pop(context),
                icon: const Icon(
                  Icons.close,
                ),
              ),

              //
              AwesomeFlashButton(state: state),
            ],
          );
        },
      ),
    );
  }
}

实现30秒自动停止录制的方法

要实现这个功能,你需要通过监听录制状态并使用定时器来触发停止操作,具体步骤如下:

  1. 将MyCameraAwesome从StatelessWidget改为StatefulWidget,因为需要维护定时器的状态
  2. 添加定时器变量,用于控制录制时长
  3. 在相机状态变化时监听录制开始/结束事件,启动或取消定时器
  4. 页面销毁时清理定时器,避免内存泄漏

修改后的完整代码如下:

import 'dart:io';
import 'dart:async';
import 'package:camerawesome/camerawesome_plugin.dart';
import 'package:camerawesome/pigeon.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
import 'package:tymelyne/AddPosts/MediaBank/MainMediaBankScreen.dart';
import 'package:tymelyne/AddPosts/MediaBank/MediaBankFullScreen.dart';
import 'package:tymelyne/Controllers/AuthDBController.dart';
import 'package:tymelyne/Universal/Widgets/UniversalWidgets.dart';
import '../Universal/Controllers/PersistController.dart';

// Instances
final _universalWidgets = UniversalWidgets();
final _persistControllerUNI = Get.find<PersistControllerUNI>();

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

  @override
  State<MyCameraAwesome> createState() => _MyCameraAwesomeState();
}

class _MyCameraAwesomeState extends State<MyCameraAwesome> {
  // 用于控制录制时长的定时器
  Timer? _recordingTimer;

  @override
  void dispose() {
    // 页面销毁时取消定时器,避免内存泄漏
    _recordingTimer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CameraAwesomeBuilder.awesome(
        enablePhysicalButton: true,
        progressIndicator: Center(
          child: _universalWidgets.customProgressIndicator(),
        ),
        availableFilters: awesomePresetFiltersList,
        // 监听相机状态变化,处理录制开始/结束逻辑
        onStateChanged: (state) {
          if (state is VideoRecordingState) {
            // 开始录制时启动30秒定时器
            _recordingTimer = Timer(const Duration(seconds: 30), () {
              state.stopRecording();
            });
          } else {
            // 录制停止(手动或自动)时取消定时器
            _recordingTimer?.cancel();
          }
        },
        saveConfig: SaveConfig.photoAndVideo(
          initialCaptureMode: CaptureMode.photo,
          mirrorFrontCamera: true,
          photoPathBuilder: (sensors) async {
            final Directory extDir = await getApplicationDocumentsDirectory();
            final testDir = await Directory(
              '${extDir.path}/xyzapp',
            ).create(recursive: true);

            if (sensors.length == 1) {
              final String filePath =
                  '${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.jpg';

              _persistControllerUNI.updateAndPersistMediaBank(
                filePath: filePath,
                fileType: 'image',
              );

              return SingleCaptureRequest(filePath, sensors.first);
            } else {
              return MultipleCaptureRequest(
                {
                  for (final sensor in sensors)
                    sensor:
                        '${testDir.path}/${sensor.position == SensorPosition.front ? 'front_' : "back_"}${DateTime.now().millisecondsSinceEpoch}.jpg',
                },
              );
            }
          },
          videoPathBuilder: (sensors) async {
            final Directory extDir = await getApplicationDocumentsDirectory();
            final testDir = await Directory(
              '${extDir.path}/xyzapp',
            ).create(recursive: true);
            if (sensors.length == 1) {
              final String filePath =
                  '${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.mp4';

              _persistControllerUNI.updateAndPersistMediaBank(
                filePath: filePath,
                fileType: 'video',
              );
              return SingleCaptureRequest(filePath, sensors.first);
            } else {
              return MultipleCaptureRequest(
                {
                  for (final sensor in sensors)
                    sensor:
                        '${testDir.path}/${sensor.position == SensorPosition.front ? 'front_' : "back_"}${DateTime.now().millisecondsSinceEpoch}.jpg',
                },
              );
            }
          },
          videoOptions: VideoOptions(
            enableAudio: true,
            quality: VideoRecordingQuality.highest,
          ),
          exifPreferences: ExifPreferences(
            saveGPSLocation: false,
          ),
        ),
        sensorConfig: SensorConfig.single(
          sensor: Sensor.position(SensorPosition.back),
          flashMode: FlashMode.none,
          aspectRatio: CameraAspectRatios.ratio_16_9,
          zoom: 0.0,
        ),
        onMediaTap: (mediaCapture) {
          mediaCapture.captureRequest.when(
            single: (single) async {
              if (single.file != null) {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const MainMediaBankScreen(),
                  ),
                );

                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const MediaBankFullScreen(
                      initialPageIndex: 0,
                    ),
                  ),
                );
              }
            },
          );

          _persistControllerUNI.updateIsLandscapeModeMediaBank();
        },
        topActionsBuilder: (state) {
          return AwesomeTopActions(
            state: state,
            padding: const EdgeInsets.only(
              left: 10,
              right: 10,
              top: 15,
            ),
            children: [
              IconButton(
                onPressed: () => Navigator.pop(context),
                icon: const Icon(
                  Icons.close,
                ),
              ),
              AwesomeFlashButton(state: state),
            ],
          );
        },
      ),
    );
  }
}

关键修改说明:

  • 添加了Timer? _recordingTimer变量用于控制录制时长
  • 在onStateChanged回调中监听VideoRecordingState,当进入录制状态时启动30秒定时器,定时器触发时调用state.stopRecording()停止录制
  • 当状态切换出录制状态时(比如手动停止),取消定时器
  • 在dispose方法中取消定时器,防止页面销毁后定时器仍在运行导致内存泄漏

内容的提问来源于stack exchange,提问作者Raj A

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 03:12:04