Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set Flutter CameraPreview Size "Fullscreen"

Iam using CameraPreview for measuring height of an object,But the issue was i cant able to set cameraPreview height full screen..

I have tried Positioned widget, it fills the screen but the image was stretched. I have tried Transform Widget, but height does not fills fullscreen, white space is coming.Image is not stretched.

Mycode:

final size = MediaQuery.of(context).size;
final deviceRatio = size.width / size.height;

return Stack(
            children: <Widget>[
              Transform.scale(
                scale: controller.value.aspectRatio/deviceRatio,
                child: new AspectRatio(
                  aspectRatio: controller.value.aspectRatio,
                  child: new CameraPreview(controller),
                ),
              ),);

Kindly help me to fit CameraPreview "FULLSCREEN" without image streching..

enter image description here

like image 619
Navin Kumar Avatar asked Jun 24 '19 11:06

Navin Kumar


3 Answers

CameraValue.aspectRatio returns width / height rather than height / width since 0.7.0, and CameraPreview handles AspectRatio itself now, so imo the working code snippet would be as follows:

/// only work inside WidgetsApp or MaterialApp, which introduces a MediaQuery
final scale = 1 / (controller.value.aspectRatio * MediaQuery.of(context).size.aspectRatio);
return Transform.scale(
  scale: scale,
  alignment: Alignment.topCenter,
  child: CameraPreview(controller),
);

update:

After scale by Transform the preview may paint off screen-size limit when used in a TransitionRoute. (When hosted in a CupertinoPageRoute a drag gesture will clearly show this).

So I think it would be a good idea to clip the preview to make it exactly matching the screen size.

final mediaSize = MediaQuery.of(context).size;
final scale = 1 / (controller.value.aspectRatio * mediaSize.aspectRatio);
return ClipRect(
  clipper: _MediaSizeClipper(mediaSize),
  child: Transform.scale(
    scale: scale,
    alignment: Alignment.topCenter,
    child: CameraPreview(controller),
  ),
);
class _MediaSizeClipper extends CustomClipper<Rect> {
  final Size mediaSize;
  const _MediaSizeClipper(this.mediaSize);
  @override
  Rect getClip(Size size) {
    return Rect.fromLTWH(0, 0, mediaSize.width, mediaSize.height);
  }
  @override
  bool shouldReclip(CustomClipper<Rect> oldClipper) {
    return true;
  }
}
like image 50
wangpan Avatar answered Oct 06 '22 16:10

wangpan


Issue has been solved by wrapping Centre widget in Transform widget

final size = MediaQuery.of(context).size;
final deviceRatio = size.width / size.height;
return Stack(
            children: <Widget>[
              Center(
                child:Transform.scale(
                      scale: controller.value.aspectRatio/deviceRatio,
                      child: new AspectRatio(
                       aspectRatio: controller.value.aspectRatio,
                       child: new CameraPreview(controller),
                       ),
                   ),),);
like image 42
Navin Kumar Avatar answered Oct 06 '22 16:10

Navin Kumar


Unfortunately both Wangpan and Navin Kumar's answers did not work for me. But the following solution did work for me.

I have two state widget fields: The cameraControllerKey, used to make a reference to the Container holding the CameraPreview. The cameraPreviewScale used to store the size of the original cameraPreview.

In my build method I first let the CameraView build its UI and set the scale to 1, meaning that I just let it draw itself as it comes (so not full screen... Yet). Also note that i set the key to my GlobalKey cameraControllerKey. In the addPostFrameCallback method I calculate the scale based on the Container view size that holds the CameraPreview and the actual screenSize. I hope it helps for you, happy fluttering.

///field in widget state
var cameraControllerKey = GlobalKey();
double? cameraPreviewScale;


/// In build method
if(cameraPreviewScale==null){
  WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
    final screenSize = MediaQuery.of(context).size;
    final previewSize = cameraControllerKey.currentContext!.size!;
    setState(() {
      cameraPreviewScale = screenSize.width / previewSize.width;    
    });
  });
}

return Scaffold(
key: _scaffoldKey,
body: 
  Stack(
    fit: StackFit.loose,
    children: [
      Center(
        child: Container(
            key: cameraControllerKey,
            child: Transform.scale(
                alignment: Alignment.center,
                scale: cameraPreviewScale ?? 1,
                child: CameraPreview(cameraController!))),
      ),
    ],
  )
);
like image 1
EvertvdBraak Avatar answered Oct 06 '22 17:10

EvertvdBraak