Place widget outside of bounding box

We Are Going To Discuss About Place widget outside of bounding box. So lets Start this Flutter Article.

Place widget outside of bounding box

How to solve Place widget outside of bounding box

One approach you can use to achieve what you want is Overlay widget since it’s non-modal and also does’t require layout/size changes to have hit testable items.
Based on your question I assume this flow is what want:
animated image showing sample
Insert an overlay entry once the pointer has entered the widget and remove it once it leaves
@override Widget build(BuildContext context) { return Scaffold( body: Center( child: Stack( children: [ MouseRegion( onEnter: (_) { Overlay.of(context)!.insert(this._overlayEntry); }, onExit: (_) => clear(), child: FloatingActionButton( key: buttonKey, onPressed: () {}, ), ), ], ), ), ); }
This is how we remove the entry, a check whether we can remove or not and a delay (for smoothing) :
Future<void> clear() async { if (!keepMenuVisible) { await Future.delayed(Duration(milliseconds: 200)); if (!keepMenuVisible) { _overlayEntry.remove(); } } }
The additional delays are used to ensure that the menu doesn’t despair reactively but instead we make it smoother.
keepMenuVisible is used to lock the menu and keep it visible once the menu it self has been hovered.
Finally, we create the entry and place the items relative to the main widget (FAB in this case):
@override void initState() { super.initState(); WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { _overlayEntry = _createOverlayEntry(); }); } OverlayEntry _createOverlayEntry() { final renderBox = buttonKey.currentContext!.findRenderObject() as RenderBox; var size = renderBox.size; var offset = renderBox.localToGlobal(Offset.zero); return OverlayEntry( builder: (_) => Positioned( left: offset.dx, top: offset.dy + size.height + 5.0, width: 200, child: MouseRegion( onEnter: (_) { keepMenuVisible = true; }, onHover: (_) { keepMenuVisible = true; }, onExit: (_) async { keepMenuVisible = false; clear(); }, child: Material( elevation: 4.0, child: ListView( padding: EdgeInsets.zero, shrinkWrap: true, children: <Widget>[ ListTile( onTap: () => print('tap action 1'), title: Text('Action 1'), ), ListTile( onTap: () => print('tap action 2'), title: Text('Action 2'), ) ], ), ), ), ), ); }
check the full sample here

Place widget outside of bounding box

One approach you can use to achieve what you want is Overlay widget since it’s non-modal and also does’t require layout/size changes to have hit testable items.
Based on your question I assume this flow is what want:
animated image showing sample
Insert an overlay entry once the pointer has entered the widget and remove it once it leaves
@override Widget build(BuildContext context) { return Scaffold( body: Center( child: Stack( children: [ MouseRegion( onEnter: (_) { Overlay.of(context)!.insert(this._overlayEntry); }, onExit: (_) => clear(), child: FloatingActionButton( key: buttonKey, onPressed: () {}, ), ), ], ), ), ); }
This is how we remove the entry, a check whether we can remove or not and a delay (for smoothing) :
Future<void> clear() async { if (!keepMenuVisible) { await Future.delayed(Duration(milliseconds: 200)); if (!keepMenuVisible) { _overlayEntry.remove(); } } }
The additional delays are used to ensure that the menu doesn’t despair reactively but instead we make it smoother.
keepMenuVisible is used to lock the menu and keep it visible once the menu it self has been hovered.
Finally, we create the entry and place the items relative to the main widget (FAB in this case):
@override void initState() { super.initState(); WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { _overlayEntry = _createOverlayEntry(); }); } OverlayEntry _createOverlayEntry() { final renderBox = buttonKey.currentContext!.findRenderObject() as RenderBox; var size = renderBox.size; var offset = renderBox.localToGlobal(Offset.zero); return OverlayEntry( builder: (_) => Positioned( left: offset.dx, top: offset.dy + size.height + 5.0, width: 200, child: MouseRegion( onEnter: (_) { keepMenuVisible = true; }, onHover: (_) { keepMenuVisible = true; }, onExit: (_) async { keepMenuVisible = false; clear(); }, child: Material( elevation: 4.0, child: ListView( padding: EdgeInsets.zero, shrinkWrap: true, children: <Widget>[ ListTile( onTap: () => print('tap action 1'), title: Text('Action 1'), ), ListTile( onTap: () => print('tap action 2'), title: Text('Action 2'), ) ], ), ), ), ), ); }
check the full sample here

Solution 1

One approach you can use to achieve what you want is Overlay widget since it’s non-modal and also does’t require layout/size changes to have hit testable items.

Based on your question I assume this flow is what want:

animated image showing sample

Insert an overlay entry once the pointer has entered the widget and remove it once it leaves

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Stack(
          children: [
            MouseRegion(
              onEnter: (_) {
                Overlay.of(context)!.insert(this._overlayEntry);
              },
              onExit: (_) => clear(),
              child: FloatingActionButton(
                key: buttonKey,
                onPressed: () {},
              ),
            ),
          ],
        ),
      ),
    );
  } 

This is how we remove the entry, a check whether we can remove or not and a delay (for smoothing) :

  Future<void> clear() async {
    if (!keepMenuVisible) {
      await Future.delayed(Duration(milliseconds: 200));
      if (!keepMenuVisible) {
        _overlayEntry.remove();
      }
    }
  }

The additional delays are used to ensure that the menu doesn’t despair reactively but instead we make it smoother.

keepMenuVisible is used to lock the menu and keep it visible once the menu it self has been hovered.

Finally, we create the entry and place the items relative to the main widget (FAB in this case):

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
      _overlayEntry = _createOverlayEntry();
    });
  }

  OverlayEntry _createOverlayEntry() {
    final renderBox = buttonKey.currentContext!.findRenderObject() as RenderBox;
    var size = renderBox.size;
    var offset = renderBox.localToGlobal(Offset.zero);

    return OverlayEntry(
      builder: (_) => Positioned(
        left: offset.dx,
        top: offset.dy + size.height + 5.0,
        width: 200,
        child: MouseRegion(
          onEnter: (_) {
            keepMenuVisible = true;
          },
          onHover: (_) {
            keepMenuVisible = true;
          },
          onExit: (_) async {
            keepMenuVisible = false;
            clear();
          },
          child: Material(
            elevation: 4.0,
            child: ListView(
              padding: EdgeInsets.zero,
              shrinkWrap: true,
              children: <Widget>[
                ListTile(
                  onTap: () => print('tap action 1'),
                  title: Text('Action 1'),
                ),
                ListTile(
                  onTap: () => print('tap action 2'),
                  title: Text('Action 2'),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }

check the full sample here

Original Author Raouf Rahiche Of This Content

Conclusion

So This is all About This Tutorial. Hope This Tutorial Helped You. Thank You.

Also Read,

ittutorial team

I am an Information Technology Engineer. I have Completed my MCA And I have 4 Year Plus Experience, I am a web developer with knowledge of multiple back-end platforms Like PHP, Node.js, Python and frontend JavaScript frameworks Like Angular, React, and Vue.

Leave a Comment