Reputation: 712
I am using Flutter + the camera package to create a photo and show it in a preview. Inside the preview the user can decide if he wants to keep / use this photo - or if he wants to repeat that shot.
Problem:
When repeating the photo, the Preview-Page shows the same image as in the first try. When using the image (sending it to an API) the user will be redirected to the page that initiated the camera call. But even there - when doing it again, the old preview is visible.
Initiating Page (Let's call it "StartPage")
SizedBox(
width: double.infinity,
child: IconButton(
icon: const Icon(Icons.camera_alt_outlined),
iconSize: 80,
color: Colors.grey,
onPressed: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PhotoPage()))
.then((value) => setState(() {}));
},
),
)
The PhotoPage shows the live camera image (Everything works fine and API call works)
class PhotoPage extends StatefulWidget {
@override
_PhotoPageState createState() => _PhotoPageState();
}
class _PhotoPageState extends State<PhotoPage> {
CameraController? cameraController;
List? cameras;
int? selectedCameraIndex;
String? imgPath;
Future initCamera(CameraDescription cameraDescription) async {
if (cameraController != null) {
await cameraController!.dispose();
}
cameraController =
CameraController(cameraDescription, ResolutionPreset.veryHigh);
cameraController!.addListener(() {
if (mounted) {
setState(() {});
}
});
if (cameraController!.value.hasError) {
print('Camera Error ${cameraController!.value.errorDescription}');
}
try {
await cameraController!.initialize();
} catch (e) {
showCameraException(e);
}
if (mounted) {
setState(() {});
}
}
Widget cameraPreview() {
if (cameraController == null || !cameraController!.value.isInitialized) {
return Text(
'Loading',
style: TextStyle(
color: Colors.white, fontSize: 20.0, fontWeight: FontWeight.bold),
);
}
return AspectRatio(
aspectRatio: cameraController!.value.aspectRatio,
child: CameraPreview(cameraController!),
);
}
Widget cameraControl(context) {
return Stack(
children: <Widget>[
Align(
alignment: Alignment.centerRight,
child: FloatingActionButton.extended(
icon: Icon(Icons.camera),
label: Text(''),
backgroundColor: Colors.green,
onPressed: () {
onCapture(context);
}))
],
//),
);
}
onCapture(context) async {
try {
var p = await getTemporaryDirectory();
var name = 'test';
var path = "${p.path}/$name.png";
XFile image = await cameraController!.takePicture();
image.saveTo(path);
await cameraController!.takePicture().then((value) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PreviewScreen(
imgPath: path,
fileName: "$name.png",
key: UniqueKey(),
))).then((value) => setState(() {}));
});
} catch (e) {
showCameraException(e);
}
}
@override
void initState() {
// TODO: implement initState
super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
]);
availableCameras().then((value) {
cameras = value;
if (cameras!.length > 0) {
setState(() {
selectedCameraIndex = 0;
});
initCamera(cameras![selectedCameraIndex!]).then((value) {});
} else {
print('No camera available');
}
}).catchError((e) {
print('Error : ${e.code}');
});
}
@override
dispose() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
]);
imgPath = '';
cameraController!.dispose();
PaintingBinding.instance!.imageCache!.clear();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Stack(children: <Widget>[
CameraPreview(cameraController!),
Align(
alignment: Alignment.bottomCenter,
child: Image(
image: new AssetImage(
"assets/layer.png",
),
)),
Align(
alignment: Alignment.bottomCenter,
child: Text(
"Please hold the phone in Landscape mode",
textAlign: TextAlign.center,
textScaleFactor: 1.3,
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
).tr(),
),
cameraControl(context),
]),
);
}
showCameraException(e) {
String errorText = 'Error ${e.code} \nError message: ${e.description}';
}
}
So I am pushing the path of the Image to the PreviewScreen:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PreviewScreen(
imgPath: path,
fileName: "$name.png",
key: UniqueKey(),
))).then((value) => setState(() {}));
});
My PreviewScreen looks as follows:
class PreviewScreen extends StatefulWidget {
String? imgPath;
String? fileName;
PreviewScreen(
{required this.imgPath, required this.fileName, required Key key})
: super(key: key);
@override
_PreviewScreenState createState() => _PreviewScreenState();
}
final SaveController controller = Get.put(SaveController());
class _PreviewScreenState extends State<PreviewScreen> {
/* @override
void initState() {
super.initState();
} */
@override
void dispose() {
SaveController().dispose();
_PreviewScreenState().dispose();
PaintingBinding.instance!.imageCache!.clear();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
//child: Stack(
//crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(children: [
Expanded(
flex: 2,
child: Image.file(
File(widget.imgPath!),
fit: BoxFit.cover,
),
)
]),
Align(
alignment: Alignment.bottomLeft,
child: FloatingActionButton.extended(
icon: Icon(Icons.repeat_outlined),
label: Text('Repeat').tr(),
backgroundColor: Colors.red,
onPressed: () {
widget.imgPath = '';
setState(() {});
Navigator.pop(context);
}
//Get.back();
),
),
Align(
alignment: Alignment.bottomRight,
child: FloatingActionButton.extended(
icon: Icon(Icons.check_circle_outline_sharp),
label: Text('Confirm').tr(),
backgroundColor: Colors.green,
onPressed: () {
SystemServices.savePhoto(widget.imgPath!)
.then((value) => setState(() {}));
},
),
),
],
),
);
}
Future getBytes() async {
Uint8List bytes = File(widget.imgPath!).readAsBytesSync();
// print(ByteData.view(buffer))
return ByteData.view(bytes.buffer);
}
}
The "Repeat"-Function looks as follows:
onPressed: () {
widget.imgPath = '';
setState(() {});
Navigator.pop(context);
}
Unfortunately, I really have no clue anymore. As far as I can see it (I am a beginner in Flutter), the state is cleared and variables are empty.
Can someone tell me, why the photo in the PreviewScreen remains the same? What am I doing wrong?
Thank you very much, I really appreciate any kind of tip.
Upvotes: 0
Views: 759
Reputation: 712
It seems like, this is the solution to for that problem:
@override
void initState() {
imageCache!.clear();
imageCache!.clearLiveImages();
super.initState();
}
Upvotes: 2