I'm trying to write a code to use the camera with Flutter, but even by following the steps seen online it cannot initialize cameraController
.
Here is my code :
class CameraPage extends StatefulWidget {
const CameraPage({Key? key}) : super(key: key);
@override
State<CameraPage> createState() => _CameraPageState();
}
class _CameraPageState extends State<CameraPage> {
late List<CameraDescription> cameras;
late CameraController cameraController;
@override
void initState() {
startCamera();
super.initState();
}
void startCamera() async {
cameras = await availableCameras();
cameraController = CameraController(
cameras[0],
ResolutionPreset.high
);
print(" Camera controller : $cameraController");
cameraController.initialize().then((value) {
if(!mounted) {
return;
}
setState(() {}); //To refresh widget
}).catchError((e) {
print(e);
});
}
@override
void dispose() {
cameraController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if(cameraController.value.isInitialized) {
return Scaffold(
body: Stack(
children: [
CameraPreview(cameraController),
],
),
);
} else {
return SizedBox();
}
}
}
The print(" Camera controller : $cameraController");
is working fine and returns me a camera controller, so it might be initialized at some point ?
CodePudding user response:
Your problem is that in the first build your camera controller is not initialized yet, because initialization is in an async method. You can use a Boolean flag to track is initialized, before accessing the late property.
bool _cameraInitialized = false;
void startCamera() async {
cameras = await availableCameras();
cameraController = CameraController(cameras[0], ResolutionPreset.high);
print(" Camera controller : $cameraController");
cameraController.initialize().then((value) {
if (!mounted) {
return;
}
setState(() {
_cameraInitialized = true; // updating the flag after camera is initialized
}); //To refresh widget
}).catchError((e) {
print(e);
});
}
@override
Widget build(BuildContext context) {
if (_cameraInitialized && cameraController.value.isInitialized) {
return Scaffold(
body: Stack(
children: [
CameraPreview(cameraController),
],
),
);
} else {
return SizedBox();
}
}
CodePudding user response:
I will suggest using FutureBuilder to handle future method.
class _CameraPageState extends State<CameraPage> {
late List<CameraDescription> cameras;
late CameraController cameraController;
@override
void initState() {
super.initState();
}
Future<void> startCamera() async {
cameras = await availableCameras();
cameraController = CameraController(cameras[0], ResolutionPreset.high);
}
late final cameraInit = Future.wait([
startCamera(),
cameraController.initialize(),
]);
@override
void dispose() {
cameraController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
FutureBuilder(
future: cameraInit,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return CameraPreview(cameraController);
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
],
),
);
}
}
Also check this cookbook.