如何在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秒自动停止录制的方法
要实现这个功能,你需要通过监听录制状态并使用定时器来触发停止操作,具体步骤如下:
- 将
MyCameraAwesome从StatelessWidget改为StatefulWidget,因为需要维护定时器的状态 - 添加定时器变量,用于控制录制时长
- 在相机状态变化时监听录制开始/结束事件,启动或取消定时器
- 页面销毁时清理定时器,避免内存泄漏
修改后的完整代码如下:
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
相关产品推荐
相关产品推荐

