如何正确初始化和处理相机控制器。我在用camera: ^0.9.4+5
与许多人一起
其他错误 https://stackoverflow.com/questions/70592464/flutter-change-the-path-of-recorded-video
我在单击切换相机按钮时收到此错误:
======== Exception caught by widgets library =======================================================
The following CameraException was thrown building ValueListenableBuilder<CameraValue>(dirty, state: _ValueListenableBuilderState<CameraValue>#47f17):
CameraException(Disposed CameraController, buildPreview() was called on a disposed CameraController.)
这是完整的代码:
class VideoRecorderScreen extends StatefulWidget {
@override
_VideoRecorderScreenState createState() {
return _VideoRecorderScreenState();
}
//final ApplicantData applicantData;
final String videorec;
VideoRecorderScreen(this.applicationId, this.name, this.description,
this.descriptionHindi, this.videorec,
{this.isOpenSubsDashboard = false});
}
class _VideoRecorderScreenState extends State<VideoRecorderScreen> {
CameraController controller;
XFile videoPath;
List<CameraDescription> cameras;
int selectedCameraIdx = 1;
int videoElapseTime = 25;
int videoMinElapseTime = 20;
bool visibilityStop = false;
bool visibilityButtons = false;
String timer = "00:00";
CountdownTimer cd;
bool startRecording = false;
void _reset() {
videoPath = null;
_changed(false);
_changedTimer("00:00");
_changedButtonVisibility(false);
}
void _changed(bool visibility) {
if (mounted) setState(() {
visibilityStop = visibility;
});
}
void _changedTimer(String time) {
if (mounted) setState(() {
timer = time;
});
}
void _changedButtonVisibility(bool visibility) {
if (mounted) setState(() {
visibilityButtons = visibility;
});
}
void _navigateAndDisplaySelection(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VideoPlayerScreen(
videoPath: videoPath.path,
applicationId: widget.applicationId,
name: widget.name,
dateTime: selectedDate,
isOpenSubsDashboard: widget.isOpenSubsDashboard)),
);
if (result) {
_reset();
}
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) =>
showSnackBar('User Validated Successfully! Welcome ' + widget.name));
availableCameras().then((availableCameras) {
cameras = availableCameras;
if (cameras.length > 0) {
for (int i = 0; i < cameras.length; i++) {
if (cameras[i].lensDirection == CameraLensDirection.front) {
if (mounted) setState(() {
selectedCameraIdx = i;
});
}
}
_onCameraSwitched(cameras[selectedCameraIdx]).then((void v) {});
}
}).catchError((err) {
print('Error: $err.code\nError Message: $err.message');
});
}
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size.width * (2 / 3);
return WillPopScope(
onWillPop: _onBackPressed,
child: Scaffold(
key: _scaffoldKey,
appBar: AppBarWidget(
title: 'Record Your Video',
actions: [
IconButton(
icon: Icon(
Icons.call,
),
onPressed: () {
ConstantMethods.callToSupport();
}),
AppBarLogo(),
],
),
body: Builder(builder: (BuildContext buildContext) {
scaffold = Scaffold.of(buildContext);
return Container(
child: ListView(
children: <Widget>[
Center(
child: Container(
width: size / 1.5,
height: size / 1.5,
Container(
padding: EdgeInsets.all(5.0),
color: Colors.grey[850],
child: Text(
selectedDate != null ? selectedDate : "",
textAlign: TextAlign.start,
),
],
),
))
: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
VerticalSpacing(20.0),
Padding(
padding:
const EdgeInsets.only(left: 8.0, right: 8.0),
child: Text(
'Click on video icon to start the recording',
textAlign: TextAlign.justify,
FlatButton(
child: Text(' Proceed for Recording '),
onPressed: () {
if (mounted) setState(() {
startRecording = true;
});
},
),
VerticalSpacing(10.0),
FlatButton(
textColor: ThemeColors.colorPrimary,
VerticalSpacing(20.0),
],
),
startRecording
? Padding(
padding: const EdgeInsets.all(5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
_cameraTogglesRowWidget(),
_captureControlRowWidget(),
Expanded(
child: Text("$timer",
textAlign: TextAlign.end,
style: TextStyle(
fontSize: Consts.fontSizeMedium)),
),
],
),
)
: new Container(),
!visibilityButtons
? Column(
children: [
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
//alignment: Alignment.bottomRight,
children: [
IconButton(
icon: const Icon(Icons.info_outline,
size: 25.0),
color: ThemeColors.colorPrimary,
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) =>
MessageDialog(
title: "ImportantTips",
message: Languages.of(context)
.videoPreInstruction,
),
);
},
),
ToggleButtons(
borderColor: ThemeColors.colorAccent,
fillColor: Colors.lightBlue[100],
borderWidth: 1,
selectedBorderColor: ThemeColors.colorAccent,
selectedColor: Colors.blue[900],
color: ThemeColors.colorPrimary,
borderRadius: BorderRadius.circular(10),
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
left: 12.0, right: 8.0),
child: Text(
'In English',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: Consts.fontSizeSmall),
),
),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0),
child: Text(
'हिंदी में ',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: Consts.fontSizeSmall),
),
),
],
onPressed: (int index) {
if(this.mounted) setState(() {
for (int i = 0;
i < isSelectedLanguage.length;
i++) {
if (i == index) {
isSelectedLanguage[i] = true;
} else {
isSelectedLanguage[i] = false;
}
}
if (isSelectedLanguage[0]) {
changeLanguage(context, 'en');
} else if (isSelectedLanguage[1]) {
changeLanguage(context, 'hi');
}
});
},
isSelected: isSelectedLanguage,
)
]),
VerticalSpacing(10.0),
Padding(
padding:
const EdgeInsets.only(left: 8.0, right: 8.0),
child
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
OutlineButton(
padding: EdgeInsets.all(5.0),
splashColor: Colors.blue[300],
borderSide:
BorderSide(color: ThemeColors.colorPrimary),
child: Text(' Retake Video ',
style: TextStyle(
color: Colors.blue,
fontSize: Consts.fontSizeMedium)),
onPressed: () {
_reset();
},
),
HorizontalSpacing(10.0),
FlatButton(
padding: EdgeInsets.all(5.0),
color: ThemeColors.colorPrimary,
// splashColor: Colors.greenAccent,
textColor: ThemeColors.white,
child: Text(' Play Recording ',
style:
TextStyle(fontSize: Consts.fontSizeMedium)),
onPressed: () {
if(videoPath!=null) {
_navigateAndDisplaySelection(context);
} else{
//ConstantMethods.showToast("Technical exception with camera.");
ConstantMethods.showToast("There is some issue in recording video right now, please try again later.");
_onBackPressed();
}
},
),
],
),
VerticalSpacing(10.0),
],
));
})),
);
}
IconData _getCameraLensIcon(CameraLensDirection direction) {
switch (direction) {
case CameraLensDirection.back:
return Icons.camera_rear;
case CameraLensDirection.front:
return Icons.camera_front;
case CameraLensDirection.external:
return Icons.camera;
default:
return Icons.device_unknown;
}
}
// Display 'Loading' text when the camera is still loading.
Widget _cameraPreviewWidget(var size) {
if (controller == null || !controller.value.isInitialized) {
return const Text(
'Loading',
style: TextStyle(
color: ThemeColors.white,
fontSize: 20.0,
fontWeight: FontWeight.w900,
),
);
}
return Container(
width: size,
height: size,
child: ClipRect(
child: OverflowBox(
alignment: Alignment.center,
child: FittedBox(
fit: BoxFit.fitWidth,
child: Container(
width: size,
height: size / controller.value.aspectRatio,
// height: size / controller.value.aspectRatio,
child: CameraPreview(controller),
// this is my CameraPreview
),
),
),
),
);
}
/// Display a row of toggle to select the camera (or a message if no camera is available).
Widget _cameraTogglesRowWidget() {
if (cameras == null) {
return Row();
}
CameraDescription selectedCamera =
cameras[selectedCameraIdx];
CameraLensDirection lensDirection =
selectedCamera.lensDirection;
//CameraLensDirection lensDirection = CameraLensDirection.front;
return Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: FlatButton.icon(
onPressed: controller != null && controller.value.isRecordingVideo
? null
: _onSwitchCamera,
icon: Icon(_getCameraLensIcon(lensDirection)),
label: Text(
"${lensDirection.toString().substring(lensDirection.toString().indexOf('.') + 1)}")),
),
);
}
/// Display the control bar with buttons to record videos.
Widget _captureControlRowWidget() {
return Expanded(
child: Align(
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IconButton(
icon: const Icon(Icons.videocam, size: 40.0),
color: ThemeColors.colorPrimary,
onPressed: controller != null &&
controller.value.isInitialized &&
!controller.value.isRecordingVideo &&
videoPath == null
? _onRecordButtonPressed
: null,
),
IconButton(
icon: const Icon(Icons.stop, size: 40.0),
color: ThemeColors.red,
onPressed: controller != null &&
controller.value.isInitialized &&
controller.value.isRecordingVideo &&
visibilityStop
? _onStopButtonPressed
: null,
),
// : new Container(),
],
),
),
);
}
String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();
Future<void> _onCameraSwitched(CameraDescription description) async {
if (description == null) {
return;
}
if(!(controller != null && controller.value.isRecordingVideo)){
onNewCameraSelected(description);
}
}
void onNewCameraSelected(CameraDescription cameraDescription) async {
if (controller != null) {
await controller.dispose();
}
controller = CameraController(
cameraDescription, ResolutionPreset.low
);
//controller = cameraController;
// If the controller is updated then update the UI.
controller.addListener(() {
if (mounted) setState(() {});
if (controller.value.hasError) {
Fluttertoast.showToast(
msg: 'Camera error ${controller.value.errorDescription}',
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: ThemeColors.red,
textColor: ThemeColors.white);
}
});
try {
await controller.initialize();
} on CameraException catch (e) {
_showCameraException(e);
}
if (mounted) {
setState(() {});
}
}
void _onSwitchCamera() {
selectedCameraIdx =
selectedCameraIdx < cameras.length - 1 ? selectedCameraIdx + 1 : 0;
CameraDescription selectedCamera = cameras[selectedCameraIdx];
_onCameraSwitched(selectedCamera);
if (mounted) setState(() {
selectedCameraIdx = selectedCameraIdx;
});
}
void _onRecordButtonPressed() {
_startVideoRecording().then((_) {
/*if (mounted) setState(() {});*/
//if (filePath != null) {
final df = new DateFormat('dd-MM-yyyy hh:mm a');
String date = df.format(new DateTime.now());
if (mounted) setState(() {
// selectedDate = date1.replaceAll("/", "-");
selectedDate = date;
});
Fluttertoast.showToast(
msg: 'Recording video started',
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: ThemeColors.grey,
textColor: ThemeColors.white);
// }
});
}
void _onStopButtonPressed() {
if (cd.isRunning) {
cd.cancel();
}
_stopVideoRecording().then((file) {
if (mounted) setState(() {});
if (file != null) {
showInSnackBar('Video recorded to ${file.path}');
videoPath = file;
}
});
}
Future<void> _startVideoRecording() async {
//final CameraController? cameraController = controller;
if (controller == null || !controller.value.isInitialized) {
//showInSnackBar('Error: select a camera first.');
Fluttertoast.showToast(
msg: 'Please wait',
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: ThemeColors.grey,
textColor: ThemeColors.white);
return;
}
if (controller.value.isRecordingVideo) {
// A recording is already started, do nothing.
return;
}
try {
cd = CountdownTimer(
new Duration(seconds: videoElapseTime), new Duration(seconds: 1));
// var sub = cd.listen(null);
var sub = cd.listen(null);
sub.onData((duration) {
// setState(() { _current = _start - duration.elapsed.inSeconds; });
if (duration.elapsed.inSeconds == videoMinElapseTime) {
// ((videoElapseTime - 5) < 20 ? 20 : (videoElapseTime - 5))) {
_changed(true);
}
timer = duration.elapsed.inMinutes.toString().padLeft(2, '0') +
":" +
duration.elapsed.inSeconds.toString().padLeft(2, '0');
_changedTimer(timer + "/00:" + videoElapseTime.toString());
print(timer);
});
sub.onDone(() {
print("Done");
_onStopButtonPressed();
sub.cancel();
});
await controller.startVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
return;
}
}
Future<XFile> _stopVideoRecording() async {
if (controller == null || !controller.value.isRecordingVideo) {
return null;
}
try {
_changedButtonVisibility(true);
XFile video = await controller.stopVideoRecording();
await GallerySaver.saveVideo(video.path); //for testing
return video;
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
}
void _showCameraException(CameraException e) {
String errorText = 'Error: ${e.code}\nError Message: ${e.description}';
print(errorText);
}
Future<bool> _onBackPressed() {
if (widget.isOpenSubsDashboard && (role == null || role.isEmpty)) {
//subscriber
return Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => SubscriberDashboard()),
(route) => false,
) ??
false;
} else {
//Navigator.of(context).pop();
return Future.value(Navigator.of(context).canPop());
}
}