Tricky question, hoping someone has a nice thought.
I call showMenu(...) on my text button in flutter, which works well.
However, sometimes during screen resizing, the menu gets stuck somewhere on the screen (away from its intended position). Sometimes it follows its anchored position. Very odd, and I noticed this behavior with the dropdown menu too.
Here is my sample code. I want to either move the menu always with the screen, or in worst case, hide the menu on a screen resizing event. Any thoughts on how to do either would be great!
class ZHomeMenuBar extends StatefulWidget {
const ZHomeMenuBar({Key? key}) : super(key: key);
@override
State<ZHomeMenuBar> createState() => _ZHomeMenuBarState();
}
class _ZHomeMenuBarState extends State<ZHomeMenuBar> {
final GlobalKey _mesKey = GlobalKey();
final GlobalKey _accKey = GlobalKey();
@override
Widget build(BuildContext context) {
final zuser = Provider.of<ZUser?>(context);
return Container(
height: 66,
decoration: BoxDecoration(color: context.backgroundColor),
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
Text(zuser == null ? "" : zuser.displayName ?? ""),
const Spacer(),
ZTextButton(text: "Portfolio", onPressed: () => {}),
context.sh,
ZTextButton(
key: _mesKey,
text: "Messages",
onPressed: () {
_showMessage(context);
}),
context.sh,
ZTextButton(key: _accKey, text: "Account", onPressed: () {}),
context.sh,
],
),
);
}
_showMessage(context) {
final RenderBox renderBox =
_mesKey.currentContext?.findRenderObject() as RenderBox;
final Size size = renderBox.size;
final Offset offset = renderBox.localToGlobal(Offset.zero);
showMenu(
context: context,
position: RelativeRect.fromLTRB(offset.dx, offset.dy + size.height,
offset.dx + size.width, offset.dy + size.height),
items: [
PopupMenuItem<String>(child: const Text('menu option 1'), value: '1'),
PopupMenuItem<String>(child: const Text('menu option 2'), value: '2'),
PopupMenuItem<String>(child: const Text('menu option 3'), value: '3'),
]);
}
}
In order to hide the menu when you're resizing the screen, you can use dart:html's window object to add an event listener to the browser's resize and pop the context of the menu.
Here is the updated code for your ZHomeMenuBar widget:
class ZHomeMenuBar extends StatefulWidget {
...
}
class _ZHomeMenuBarState extends State<ZHomeMenuBar> {
...
Timer? timer;
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (kIsWeb) {
final int debounceDuration = 100;
html.window.addEventListener("resize", (_) {
final modalRoute = ModalRoute.of(context);
if (modalRoute == null) {
return;
}
if (!modalRoute.isCurrent) {
Navigator.pop(context);
if (timer != null && timer!.isActive) {
timer!.cancel();
}
timer = Timer(Duration(milliseconds: 100), () {
_showMessage(context);
});
}
});
}
}
@override
void dispose() {
super.dispose();
timer?.cancel();
}
@override
Widget build(BuildContext context) {
...
}
_showMessage(context) {
...
}
}
So what the code in the didChangeDependencies method does is:
ModalRoute of the context is obtained.ModalRoute is nullisCurrent property of the ModalRoute is checked. If it is false, it means the ModalRoute isn't the top-most route on the navigator and that means there is a dialog on the screen.isCurrent is false, we pop the context (this removes the dialog), and set a short timer with the debounceDuration and then show the dialog. This uses the newly recalculated dimensions and shows the dialog at the right position.timer variable.You can update the debounceDuration as you need.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With