Skip to content

Instantly share code, notes, and snippets.

@ambrizals
Last active June 17, 2022 03:04
Show Gist options
  • Save ambrizals/3c32c45750426e8960d4b5f5a105b3be to your computer and use it in GitHub Desktop.
Save ambrizals/3c32c45750426e8960d4b5f5a105b3be to your computer and use it in GitHub Desktop.
Create custom popup menu
import 'package:flutter/material.dart';
class ButtonPopupMenu extends StatefulWidget {
final Text label;
final Icon? icon;
final Widget content;
final double width;
final double height;
const ButtonPopupMenu(
{Key? key,
this.icon,
required this.content,
required this.label,
this.width = 300,
this.height = 300})
: super(key: key);
@override
State<ButtonPopupMenu> createState() => _ButtonPopupMenuState();
}
class _ButtonPopupMenuState extends State<ButtonPopupMenu>
with SingleTickerProviderStateMixin {
final GlobalKey _key = GlobalKey<State>();
OverlayEntry? _entry;
bool status = false;
void _closeMenu() {
_entry?.remove();
_entry = null;
setState(() {
status = false;
});
}
void _openMenu() {
RenderBox? renderBox =
_key.currentContext?.findRenderObject() as RenderBox?;
if (renderBox != null) {
final offset = renderBox.localToGlobal(Offset.zero);
final buttonSize = renderBox.size;
_entry = _overlayEntryBuilder(offset, buttonSize);
if (_entry != null) {
Overlay.of(context)?.insert(_entry!);
setState(() {
status = true;
});
}
}
}
OverlayEntry _overlayEntryBuilder(Offset offset, Size buttonSize) {
return OverlayEntry(
builder: (_) => Stack(children: [
Positioned.fill(
child: GestureDetector(
onTapDown: (_) => _closeMenu(),
)),
Positioned(
top: offset.dy + buttonSize.height,
left: offset.dx,
width: widget.width,
child: Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Container(
height: widget.height,
width: widget.width,
decoration: BoxDecoration(
color: Colors.white,
// borderRadius: _borderRadius,
),
child: widget.content,
),
),
],
),
),
]),
);
}
@override
Widget build(BuildContext context) {
return IgnorePointer(
ignoring: _entry != null ? true : false,
child: InkWell(
key: _key,
onTap: () => _openMenu(),
child: Container(
child: Row(
children: [
if (widget.icon != null) widget.icon!,
widget.label,
Text(status.toString()),
],
),
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment