import 'package:flutter/material.dart'; class AnchoredOverlay extends StatelessWidget { final bool showOverlay; final Widget Function(BuildContext, Offset anchor) overlayBuilder; final Widget child; const AnchoredOverlay({ super.key, required this.showOverlay, required this.overlayBuilder, required this.child, }); @override Widget build(BuildContext context) { return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { return OverlayBuilder( showOverlay: showOverlay, overlayBuilder: (BuildContext overlayContext) { RenderBox box = context.findRenderObject() as RenderBox; final center = box.size.center(box.localToGlobal(const Offset(0.0, 0.0))); return overlayBuilder(overlayContext, center); }, child: child, ); }); } } class OverlayBuilder extends StatefulWidget { final bool showOverlay; final Widget Function(BuildContext) overlayBuilder; final Widget child; const OverlayBuilder({ super.key, this.showOverlay = false, required this.overlayBuilder, required this.child, }); @override State createState() => _OverlayBuilderState(); } class _OverlayBuilderState extends State { OverlayEntry? overlayEntry; @override void initState() { super.initState(); if (widget.showOverlay) { WidgetsBinding.instance.addPostFrameCallback((_) => showOverlay()); } } @override void didUpdateWidget(OverlayBuilder oldWidget) { super.didUpdateWidget(oldWidget); WidgetsBinding.instance.addPostFrameCallback((_) => syncWidgetAndOverlay()); } @override void reassemble() { super.reassemble(); WidgetsBinding.instance.addPostFrameCallback((_) => syncWidgetAndOverlay()); } @override void dispose() { if (isShowingOverlay()) { hideOverlay(); } super.dispose(); } bool isShowingOverlay() => overlayEntry != null; void showOverlay() { overlayEntry = OverlayEntry( builder: widget.overlayBuilder, ); addToOverlay(overlayEntry!); } void addToOverlay(OverlayEntry entry) async { print('addToOverlay'); Overlay.of(context).insert(entry); } void hideOverlay() { print('hideOverlay'); if (overlayEntry != null) { overlayEntry!.remove(); overlayEntry = null; } } void syncWidgetAndOverlay() { if (isShowingOverlay() && !widget.showOverlay) { hideOverlay(); } else if (!isShowingOverlay() && widget.showOverlay) { showOverlay(); } } @override Widget build(BuildContext context) { return widget.child; } }