Search code examples
fluttercamerarectanglesbounding-box

Flutter how to draw pressable rectangle on camera feed?


I'm using camera plug-in to get the camera feed. Every 10 seconds, I generate 4 values (x,y,w,h) and draw a rectangle (only the border, the inside is transparent) on the screen (with random text). If the user clicks on this box, it disappears.

It looks something like this image. (x,y,w,h) and the text are randomly generated.

enter image description here

Is this possible to do this using camera plugin? Or is there another package that already does this?


Solution

  • Camera plugin does not have any feature to draw over the preview, but you can make something like that with Stack widget and containers.

    Here's a quick and dirty example, but hopefully will give you the idea:

    class CameraApp extends StatefulWidget {
      @override
      _CameraAppState createState() => _CameraAppState();
    }
    
    class _CameraAppState extends State<CameraApp> {
      CameraController controller;
    
      // Holds the position information of the rectangle
      Map<String, double> _position = {
        'x': 0,
        'y': 0,
        'w': 0,
        'h': 0,
      };
    
      // Whether or not the rectangle is displayed
      bool _isRectangleVisible = false;
    
      Future<void> getCameras() async {
        final cameras = await availableCameras();
        controller = CameraController(cameras[0], ResolutionPreset.medium);
        controller.initialize().then((_) {
          if (!mounted) {
            return;
          }
          setState(() {});
        });
      }
    
      // Some logic to get the rectangle values
      void updateRectanglePosition() {
        setState(() {
          // assign new position
          _position = {
            'x': 0,
            'y': 0,
            'w': 0,
            'h': 0,
          };
          _isRectangleVisible = true;
        });
      }
    
      @override
      void initState() {
        getCameras();
        super.initState();
      }
    
      @override
      void dispose() {
        controller?.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        if (!controller.value.isInitialized) {
          return Container();
        }
        return Stack(
          children: [
            AspectRatio(
              aspectRatio: controller.value.aspectRatio,
              child: controller == null ? Container() : CameraPreview(controller),
            ),
            if (_isRectangleVisible)
              Positioned(
                left: _position['x'],
                top: _position['y'],
                child: InkWell(
                  onTap: () {
                    // When the user taps on the rectangle, it will disappear
                    setState(() {
                      _isRectangleVisible = false;
                    });
                  },
                  child: Container(
                    width: _position['w'],
                    height: _position['h'],
                    decoration: BoxDecoration(
                      border: Border.all(
                        width: 2,
                        color: Colors.blue,
                      ),
                    ),
                    child: Align(
                      alignment: Alignment.topLeft,
                      child: Container(
                        color: Colors.blue,
                        child: Text(
                          'hourse -71%',
                          style: TextStyle(color: Colors.white),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
          ],
        );
      }
    }