skip to Main Content

I’m developing a Flutter app where I use an OverlayEntry to display a dropdown-like widget below a button when it is clicked. However, the content of the overlay has dynamic height based on the items inside. If there’s not enough space below the button, I want the overlay to be positioned above the button instead of expanding off the screen.

The main challenge is dynamically calculating the space above and below the button and deciding whether the overlay should go above or below based on the available space. I’ve already used RenderBox to get the button’s position and size, but I’m having trouble efficiently positioning the overlay when the height of the overlay is dynamic.

Below the Button: The overlay should appear below the button if there is enough space.

Above the Button: If there is not enough space below, the overlay should appear above the button.

The overlay should dynamically adjust its height to fit within the available space without overflowing the screen.

2

Answers


  1. To solve your problem, I would have divided it into four steps:

    • I will use RenderBox to get the size and position of the button
    • I will calculate the available space above and below the button by checking the height of the screen and the position of the button to know if we can display the Overlay.
    • Depending on the available space that I calculated in the step 2 I will decide if the Overlay should be placed above or below the button
    • And finally, I display the Overlay in the right position, making sure that it fits well in the interface.

    Hope this helps you.

    Login or Signup to reply.
  2. Here is an example of code that you should adapt to your environment

    class DynamicOverlayDropdown extends StatefulWidget {
      @override
      _DynamicOverlayDropdownState createState() => _DynamicOverlayDropdownState();
    }
    
    class _DynamicOverlayDropdownState extends State<DynamicOverlayDropdown> {
      OverlayEntry? _overlayEntry;
      final GlobalKey _buttonKey = GlobalKey();
    
      void _showOverlay() {
        if (_overlayEntry != null) {
          _overlayEntry!.remove();
          _overlayEntry = null;
          return;
        }
    
        RenderBox button = _buttonKey.currentContext!.findRenderObject() as RenderBox;
        Offset buttonPosition = button.localToGlobal(Offset.zero);
        Size buttonSize = button.size;
    
        double screenHeight = MediaQuery.of(context).size.height;
        double availableAbove = buttonPosition.dy;
        double availableBelow = screenHeight - (buttonPosition.dy + buttonSize.height);
    
        // Height of content to be calculated dynamically based on the elements
        double overlayHeight = 200; 
    
        //  Determine the position of the overlay
        bool showAbove = (overlayHeight <= availableBelow) ? false : (overlayHeight <= availableAbove);
    
        _overlayEntry = OverlayEntry(
          builder: (context) {
            return Positioned(
              top: showAbove ? buttonPosition.dy - overlayHeight : buttonPosition.dy + buttonSize.height,
              left: buttonPosition.dx,
              width: buttonSize.width,
              child: Material(
                elevation: 4.0,
                child: Container(
                  height: overlayHeight,
                  color: Colors.white,
                  child: ListView.builder(
                    itemCount: 10, // Replace with dynamic number of elements
                    itemBuilder: (context, index) {
                      return ListTile(title: Text('Element $index'));
                    },
                  ),
                ),
              ),
            );
          },
        );
    
        Overlay.of(context)!.insert(_overlayEntry!);
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              key: _buttonKey,
              onPressed: _showOverlay,
              child: Text('Display the Dropdown'),
            ),
          ],
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search