Constrainting layout to not go out of bounds with Positioned widget

537 views Asked by At

I am currently working on a layout that displays a Positioned widget on the entire screen. It's positioning itself close to the detected barcode, Look at the image below for an example.

UI example

But when the barcode moves to close the the left edge of the screen, the UI elements are drawn partially offscreen. Is there a way I can fix this without having to calculate when I am going out of bounds each frame?

Overflow example

Here is the code that I use to set this up:

Widget _buildImage() {
    return Container(
      constraints: const BoxConstraints.expand(),
      child: _controller == null
          ? const Center(
              child: Text(
                'Initializing Camera...',
                style: TextStyle(
                  color: Colors.green,
                  fontSize: 30.0,
                ),
              ),
            )
          : Stack(
              fit: StackFit.expand,
              children: <Widget>[
                CameraPreview(_controller!),
                _buildResults(),
                if (_scanResults.isNotEmpty)
                   _buildUIElements()

              ],
            ),
    );
  }

  Widget _buildUIElements() {
    Barcode barcode = _scanResults[0];
    final Size imageSize = Size(
      _controller!.value.previewSize!.height,
      _controller!.value.previewSize!.width,
    );
    var boundingBox = barcode.boundingBox!;
    var rect = scaleRect(rect: boundingBox, imageSize: imageSize, widgetSize: MediaQuery.of(context).size);
    return AnimatedPositioned(
      top: rect.bottom,
      left: rect.left,
      child: Card(
        child: Text('This is an amaizing product'),
      ),
      duration: const Duration(milliseconds: 500),
    );
  }

Maybe there is a better way to achieve this?

Don't mind the excessive use of ! still learning the whole null-safety thing :)

EDIT 1: As suggested by pskink I have looked at how the tooltips in flutter work and made use of the SingleChildLayoutDelegate in combination with a CustomSingleChildLayout and this works perfectly for tracking the position but now there is no option to animate this.

My delegate class is as follows:

class CustomSingleChildDelegate extends SingleChildLayoutDelegate {

  CustomSingleChildDelegate ({
    required this.target,
    required this.verticalOffset,
    required this.preferBelow,
  });

  final Offset target;

  final double verticalOffset;

  final bool preferBelow;

  @override
  BoxConstraints getConstraintsForChild(BoxConstraints constraints) => constraints.loosen();

  @override
  Offset getPositionForChild(Size size, Size childSize) {
    return positionDependentBox(
      size: size,
      childSize: childSize,
      target: target,
      verticalOffset: verticalOffset,
      preferBelow: preferBelow,

    );
  }

  @override
  bool shouldRelayout(CustomSingleChildDelegate oldDelegate) {
    return target != oldDelegate.target
        || verticalOffset != oldDelegate.verticalOffset
        || preferBelow != oldDelegate.preferBelow;
  }
}

And then updated my builder function with:

return CustomSingleChildLayout(
        delegate: CustomSingleChildDelegate (target: rect.bottomCenter, verticalOffset: 20, preferBelow: true),
        child: Card(
            child: Text('This is an amaizing product'),
          ),
      )

Having the AnimatedPositioned as child of the layout causes an exception.

0

There are 0 answers