我有一个TextFormField。通常,您可以使用选择工具栏通过长按/双击来复制/粘贴/全选等。
我想覆盖粘贴事件。它不应该简单地插入当前剪贴板数据,而是打开一个弹出窗口,其中包含多个要插入的选项。
是否可以以任何方式捕获并覆盖粘贴事件?我看到类似handlePaste()for 的东西SelectionControls,但我不知道如何将其添加到我的TextFormField.
提前致谢!
AFAIK,您无法完全“拦截”标准工具栏。但是,您可以做的是阻止标准工具栏并创建您自己的工具栏。
您可以使用将文本字段/文本表单字段包装在 IgnorePointer 下。它将隐藏文本字段上的所有点击手势。下面是代码片段。
IgnorePointer(
child: TextField(
focusNode: _textfieldFocusNode,
controller: _controller,
),
)
Run Code Online (Sandbox Code Playgroud)
现在,您可以将此 IgnorePointer 包装在 GestureDetector 下并显示您自己的菜单。像这样 :
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
FocusScope.of(context).requestFocus(_textfieldFocusNode);
},
onLongPress: () {
showMenu(____
}
)
Run Code Online (Sandbox Code Playgroud)
这会产生下面的结果,示例实现代码在这里
由于 flutter 3.7 @Arenukvern 答案已被弃用。相反,可以使用contextMenuBuilder覆盖工具栏事件:
TextFormField(
...
/// Override default input action toolbar to catch paste event
contextMenuBuilder: (BuildContext context, EditableTextState editableTextState) {
return AdaptiveTextSelectionToolbar.editable(
anchors: editableTextState.contextMenuAnchors,
clipboardStatus: ClipboardStatus.pasteable,
// to apply the normal behavior when click on copy (copy in clipboard close toolbar)
// use an empty function `() {}` to hide this option from the toolbar
onCopy: () => editableTextState.copySelection(SelectionChangedCause.toolbar),
// to apply the normal behavior when click on cut
onCut: () => editableTextState.cutSelection(SelectionChangedCause.toolbar),
onPaste: () {
// HERE will be called when the paste button is clicked in the toolbar
// apply your own logic here
// to apply the normal behavior when click on paste (add in input and close toolbar)
editableTextState.pasteText(SelectionChangedCause.toolbar);
},
// to apply the normal behavior when click on select all
onSelectAll: () => editableTextState.selectAll(SelectionChangedCause.toolbar),
);
},
...
)
Run Code Online (Sandbox Code Playgroud)
这应该与除网络之外的所有平台兼容(源)
找到了一种覆盖粘贴事件的方法。我不确定这是一种正确的方法,但它确实有效。
在每个 TextField 中都有SelectionControls,它提供了一种显示和处理工具栏控件的方法。
因此,首先要捕获粘贴事件:
class AppCupertinoTextSelectionControls extends CupertinoTextSelectionControls {
AppCupertinoTextSelectionControls({
required this.onPaste,
});
ValueChanged<TextSelectionDelegate> onPaste;
@override
Future<void> handlePaste(final TextSelectionDelegate delegate) {
onPaste(delegate);
return super.handlePaste(delegate);
}
}
class AppMaterialTextSelectionControls extends MaterialTextSelectionControls {
AppMaterialTextSelectionControls({
required this.onPaste,
});
ValueChanged<TextSelectionDelegate> onPaste;
@override
Future<void> handlePaste(final TextSelectionDelegate delegate) {
onPaste(delegate);
return super.handlePaste(delegate);
}
}
Run Code Online (Sandbox Code Playgroud)
TextSelectionControls? _selectionControls;
@override
void initState() {
if (widget.onPaste != null) {
if (Platform.isIOS) {
_selectionControls = AppCupertinoTextSelectionControls(
onPaste: widget.onPaste!,
);
} else {
_selectionControls = AppMaterialTextSelectionControls(
onPaste: widget.onPaste!,
);
}
}
super.initState();
}
Run Code Online (Sandbox Code Playgroud)
onPaste使用带有类型的回调ValueChanged<TextSelectionDelegate>,您可以使用Flutter 团队用于获取剪贴板数据的相同代码:
Future<void> onPastePhone(final TextSelectionDelegate? delegate) async {
final TextSelection selection = phoneController.selection;
if (!selection.isValid) {
return;
}
// Snapshot the input before using `await`.
// See https://github.com/flutter/flutter/issues/11427
final ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
final text = data?.text ?? '';
if (text.isEmpty) {
return;
}
}
Run Code Online (Sandbox Code Playgroud)
然后在文本字段中使用选择控件。
TextFormField(
selectionControls: _selectionControls,
)
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你。