Reputation: 241
When a user takes a photo, I want to send it to the photo_preview screen, which gives the user the chance to take another photo.
This page is as follows:
import 'package:flutter/material.dart';
import 'dart:io';
class photo_previewScreen extends StatelessWidget {
final String imagePath;
const photo_previewScreen({Key key, this.imagePath}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Display the Picture')),
body: Image.file(File(imagePath)),
);
}
}
On my current camera page, what's the best way for me to send the photo to the above page? When the take picture button is pressed, this is what is currently happening:
onPressed: () {
_openGallery();
Navigator.pop(context);
},
EDIT: Full page with edits from the answer
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'dart:io';
import 'package:stumble/pages/PhotoPreviewScreen.dart';
class Camera extends StatefulWidget {
Function setData;
Camera({Key key, this.setData}) : super(key: key);
@override
_CameraScreenState createState() => _CameraScreenState();
}
class _CameraScreenState extends State<Camera> {
CameraController controller;
List cameras;
int selectedCameraIndex;
String imgPath;
var image;
takePicture;
Future _openGallery() async {
image = await controller.takePicture();
if (widget.setData != null) {
widget.setData(File(image.path));
}
}
@override
void initState() {
super.initState();
availableCameras().then((availableCameras) {
cameras = availableCameras;
if (cameras.length > 0) {
setState(() {
selectedCameraIndex = 0;
});
_initCameraController(cameras[selectedCameraIndex]).then((void v) {});
} else {
print('No camera available');
}
}).catchError((err) {
print('Error :${err.code}Error message : ${err.message}');
});
}
Future _initCameraController(CameraDescription cameraDescription) async {
if (controller != null) {
await controller.dispose();
}
controller = CameraController(cameraDescription, ResolutionPreset.high);
controller.addListener(() {
if (mounted) {
setState(() {});
}
if (controller.value.hasError) {
print('Camera error ${controller.value.errorDescription}');
}
});
try {
await controller.initialize();
} on CameraException catch (e) {}
if (mounted) {
setState(() {});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 1,
child: _cameraPreviewWidget(),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 120,
width: double.infinity,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[_cameraControlWidget(context), Spacer()],
),
),
)
],
),
),
),
);
}
Widget _cameraPreviewWidget() {
if (controller == null || !controller.value.isInitialized) {
return const Text(
'Loading',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w900,
),
);
}
final size = MediaQuery.of(context).size;
final deviceRatio = size.width / size.height;
return Stack(children: <Widget>[
Positioned.fill(
child: new AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: new CameraPreview(controller),
),
),
]);
}
Widget _cameraControlWidget(context) {
return Expanded(
child: Align(
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
FloatingActionButton(
child: Icon(
Icons.center_focus_strong,
size: 39,
color: Color(0xffffffff),
),
backgroundColor: Color(0xff33333D),
onPressed: () async {
var result = await takePicture();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PhotoPreviewScreen(
imagePath: result,
),
),
);
})
],
),
),
);
}
}
I am getting the error that
'The method 'takePicture isn't defined for the type '_CameraScreenState'
This despite takePicture(); being defined.
Upvotes: 1
Views: 1026
Reputation: 3326
You can navigate to the preview screen on clicking the take picture button, passing the image path:
void onTakePictureButtonPressed() async {
var result = await takePicture();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PhotoPreviewScreen(
imagePath: result,
),
),
);
}
Future<String> takePicture() async {
if (!controller.value.isInitialized) {
showErrorFlushbar(context, 'Error: select a camera first.');
return null;
}
final Directory extDir = await getApplicationDocumentsDirectory();
final String dirPath = '${extDir.path}/Pictures/ompariwar';
await Directory(dirPath).create(recursive: true);
final String filePath = '$dirPath/${timestamp()}.jpg';
if (controller.value.isTakingPicture) {
// A capture is already pending, do nothing.
return null;
}
try {
await controller.takePicture(filePath);
} on CameraException catch (e) {
print(e);
return null;
}
return filePath;
}
In the preview screen, you can do this:
class PhotoPreviewScreen extends StatelessWidget {
final String imagePath;
const PhotoPreviewScreen({Key key, this.imagePath}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () => Navigator.pop(context), // Go back to the camera to take the picture again
child: Icon(Icons.camera_alt),
),
appBar: AppBar(title: Text('Display the Picture')),
body: Column(
children: [
Expanded(child: Image.file(File(imagePath))),
SomeButton(), // Add a button to send the image to server or go back to home screen here
],
),
);
}
}
Btw it's a convention to name your class/ Widget name in UpperCamelCase. Read more on this Dart style guide for clean code.
Upvotes: 2