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