Skip to content

Instantly share code, notes, and snippets.

@DVegasa
Created January 2, 2021 09:12
Show Gist options
  • Save DVegasa/eaa982c4eacdff30fc85d5b1bad2c623 to your computer and use it in GitHub Desktop.
Save DVegasa/eaa982c4eacdff30fc85d5b1bad2c623 to your computer and use it in GitHub Desktop.
PopupMenu
import 'package:flutter/material.dart' hide showMenu;
import 'package:flutter/material.dart' as material show showMenu;
/// A mixin to provide convenience methods to record a tap position and show a popup menu.
mixin CustomPopupMenu<T extends StatefulWidget> on State<T> {
Offset _tapPosition;
/// Pass this method to an onTapDown parameter to record the tap position.
void storePosition(TapDownDetails details) =>
_tapPosition = details.globalPosition;
/// Use this method to show the menu.
Future<T> showMenu<T>({
@required BuildContext context,
@required List<PopupMenuEntry<T>> items,
T initialValue,
double elevation,
String semanticLabel,
ShapeBorder shape,
Color color,
bool captureInheritedThemes = true,
bool useRootNavigator = false,
}) {
final RenderBox overlay = Overlay.of(context).context.findRenderObject();
return material.showMenu<T>(
context: context,
position: RelativeRect.fromLTRB(
_tapPosition.dx,
_tapPosition.dy,
overlay.size.width - _tapPosition.dx,
overlay.size.height - _tapPosition.dy,
),
items: items,
initialValue: initialValue,
elevation: elevation,
semanticLabel: semanticLabel,
shape: shape,
color: color,
captureInheritedThemes: captureInheritedThemes,
useRootNavigator: useRootNavigator,
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_arch_training/CustomPopupMenu.dart';
class TwoScreen extends StatefulWidget {
static const routeName = "/OneScreen";
@override
_TwoScreenState createState() => _TwoScreenState();
}
class _TwoScreenState extends State<TwoScreen>
with AutomaticKeepAliveClientMixin<TwoScreen> {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
print("Two build");
return Scaffold(
appBar: AppBar(
title: Text("TwoScreen"),
),
body: Container(
child: Column(
children: [
DvegasaCard(),
DvegasaCard(),
DvegasaCard(),
DvegasaCard(),
DvegasaCard(),
],
),
),
);
}
}
class DvegasaCard extends StatefulWidget {
@override
_DvegasaCardState createState() => _DvegasaCardState();
}
class _DvegasaCardState extends State<DvegasaCard> with CustomPopupMenu {
bool isHighlighted = false;
void _showPopup() {
setState(() => isHighlighted = true);
this.showMenu(
color: Colors.transparent,
elevation: 0,
context: context,
items: [MyMenu()],
).then((value) {
print("showMenu clicked $value");
setState(() => isHighlighted = false);
});
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onLongPress: _showPopup,
onTapDown: storePosition,
child: Container(
color: Colors.transparent,
width: double.infinity,
child: Card(
elevation: isHighlighted ? 4 : 0,
color:
isHighlighted ? Color.fromRGBO(240, 240, 240, 1) : Colors.white,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Text(
"veh",
textAlign: TextAlign.center,
),
),
),
),
);
}
}
class MyMenu extends PopupMenuEntry<int> {
@override
_MyMenuState createState() => _MyMenuState();
@override
double get height => 100;
// height doesn't matter, as long as we are not giving
// initialValue to showMenu().
@override
bool represents(int value) => false;
}
class _MyMenuState extends State<MyMenu> {
Widget _buildItem({
@required IconData icon,
@required String label,
@required int value,
Color color = Colors.black87,
}) {
return InkWell(
onTap: () => Navigator.of(context).pop(value),
highlightColor: Colors.black.withOpacity(0.05),
splashColor: Colors.black.withOpacity(0.05),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 12),
child: Row(
children: [
Icon(
icon,
color: color,
),
SizedBox(width: 10),
Flexible(
child: Text(
label,
style: TextStyle(
color: color,
fontSize: 15,
),
),
),
],
),
),
);
}
@override
Widget build(BuildContext context) {
return Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Column(
children: [
_buildItem(
icon: Icons.alarm,
label: "Уведомить за...",
value: 1,
),
_buildItem(
icon: Icons.map_outlined,
label: "Где аудитория?",
value: 2,
),
Divider(),
_buildItem(
icon: Icons.share_outlined,
label: "Поделиться",
value: 3,
),
],
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment