Reputation: 135
The flutter (on desktop) shows this custom context menu for the text fields which is absolutely ugly:
Do you know of a way that this can be customized?
UPDATE
I actually found the answer. You have to implement a class based on TextSelectionControls
and give it to selectionControls
of the TextInputField. Also you can lookup the MaterialTextSelectionControls
which has a simple implementation to understand how it is done.
Upvotes: 8
Views: 7713
Reputation: 17804
This functionality was added in Flutter 3.7 (related Github comment).
class CustomMenuPage extends StatelessWidget {
CustomMenuPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SizedBox(
width: 300.0,
child: TextField(
maxLines: 4,
minLines: 2,
contextMenuBuilder: (context, editableTextState) {
return _MyContextMenu(
anchor: editableTextState.contextMenuAnchors.primaryAnchor,
children: [
TextSelectionToolbarTextButton(
padding: EdgeInsets.all(8),
onPressed: () {
debugPrint('Flutter');
},
child: Text('Flutter is cool'),
)
],
);
},
),
),
),
);
}
}
class _MyContextMenu extends StatelessWidget {
const _MyContextMenu({
required this.anchor,
required this.children,
});
final Offset anchor;
final List<Widget> children;
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Positioned(
top: anchor.dy,
left: anchor.dx,
child: Card(
child: Column(
children: children,
),
),
),
],
);
}
}
See the official context menu sample repo here.
Upvotes: 4
Reputation: 14470
With Flutter 3.7 you can now create custom context menus anywhere in a Flutter app.
A contextMenuBuilder
parameter has been added to many widgets (e.g. TextField
, CupertinoTextField
, SelectionArea
, etc.). You can return any widget you want from contextMenuBuilder
, including modifying the default platform-adaptive context menu.
Example: (source)
TextField(
contextMenuBuilder: (context, editableTextState) {
final TextEditingValue value = editableTextState.textEditingValue;
final List<ContextMenuButtonItem> buttonItems = editableTextState.contextMenuButtonItems;
if (isValidEmail(value.selection.textInside(value.text))) {
buttonItems.insert(
0,
ContextMenuButtonItem(
label: 'Send email',
onPressed: () {
ContextMenuController.removeAny();
Navigator.of(context).push(_showDialog(context));
},
));
}
return AdaptiveTextSelectionToolbar.buttonItems(
anchors: editableTextState.contextMenuAnchors,
buttonItems: buttonItems,
);
},
)
This new feature works outside of text selection too by using ContextMenuController
. You could, for example, create an Image widget that shows a Save button when right clicked or long pressed: (source)
ContextMenuRegion(
contextMenuBuilder: (context, offset) {
return AdaptiveTextSelectionToolbar.buttonItems(
anchors: TextSelectionToolbarAnchors(
primaryAnchor: offset,
),
buttonItems: <ContextMenuButtonItem>[
ContextMenuButtonItem(
onPressed: () {
ContextMenuController.removeAny();
Navigator.of(context).push(_showDialog(context));
},
label: 'Save',
),
],
);
},
child: const SizedBox(
width: 200.0,
height: 200.0,
child: FlutterLogo(),
),
)
You can find more examples of custom context menus in:
Upvotes: 15