Polaris
Polaris

Reputation: 712

Flutter (camera) does not refresh Photo Preview

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

Answers (1)

Polaris
Polaris

Reputation: 712

It seems like, this is the solution to for that problem:

@override
  void initState() {
    imageCache!.clear();
    imageCache!.clearLiveImages();
    super.initState();
  }

Upvotes: 2

Related Questions