Flutter TextField - 如何支持 <ENTER> _<SHIFT-ENTER>and_ 上提交 换行符



我正在开发一个包含聊天功能的Flutter Web应用程序。

我想包含一个普通的输入功能,用户可以在其中输入文本并将其发送到聊天流中。如今,聊天应用程序的一个标准功能是在<ENTER>上执行send,并在<SHIFT-ENTER>上执行换行,或其某些变体。

目前,我一次只能实现其中一个功能。如果将TextFieldkeyboardType设置为TextInputType.multiline,则<ENTER><SHIFT-ENTER>始终执行换行,则似乎无法覆盖此行为。

如果您的TextFieldTextInputType.text,您可以捕获<ENTER>并发送,但尝试捕获<SHIFT-ENTER>以添加换行符并没有成功。我尝试过通过onKey处理程序手动抓住按键,并将n插入到controller.text中,但似乎TextInputType.text根本不适用于多行,因此效果不佳。

只是想知道是否有其他开发人员遇到过这种情况,或者提出了任何合适的解决方案。理想情况下,解决方案也可以在android/ios上运行。对我来说,我决定使用TextInputType.text,暂时放弃多行功能。

感谢

这可以通过在TextField中添加FocusNode来实现。将焦点节点置于小部件的状态。

late final _focusNode = FocusNode(
onKey: (FocusNode node, RawKeyEvent evt) {
if (!evt.isShiftPressed && evt.logicalKey.keyLabel == 'Enter') {
if (evt is RawKeyDownEvent) {
_sendMessage();
}
return KeyEventResult.handled;
}
else {
return KeyEventResult.ignored;
}
},
);

build函数中,在创建TextField时添加焦点。

TextField(
autofocus: true,
controller: _textController,
focusNode: _focusNode,
)

值得一提的是,我能够想出一个合理的解决方案,我将在下面发布,以防有人自己遇到这种情况。

我将Textfield封装在一个键盘监听器中,当它看到是<Enter>时,它会调用我的onSend函数。我以前尝试过,但我想早些时候我错过了RawKeyEventDataWeb的转换,这使我能够捕获isShiftPressed,以便在不强制发送的情况下在<SHFT-ENTER>上允许新行。不幸的是,我不得不添加一些破解代码来删除按下回车键时添加的n,但这对于功能性+现代消息传递来说是一个很小的代价。

RawKeyboardListener(
focusNode: focusNode,
onKey: handleKeyPress,
child: TextField(
controller: messageController,
minLines: 1,
maxLines: null,
textInputAction: TextInputAction.done,
style: normalTextStyle,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
isDense: true,
hintText: 'Type a message',
hintStyle: TextStyle(
fontSize: 16,
color: Color(0xFF474749),
),
border: InputBorder.none,
),
),
)
void handleKeyPress(event) {
if (event is RawKeyUpEvent && event.data is RawKeyEventDataWeb) {
var data = event.data as RawKeyEventDataWeb;
if (data.code == "Enter" && !event.isShiftPressed) {
final val = messageController.value;
final messageWithoutNewLine =
messageController.text.substring(0, val.selection.start - 1) +
messageController.text.substring(val.selection.start);
messageController.value = TextEditingValue(
text: messageWithoutNewLine,
selection: TextSelection.fromPosition(
TextPosition(offset: messageWithoutNewLine.length),
),
);
_onSend();
}
}
}

这是我在TextField中使用的,用于在回车时支持换行。

class TextInputsWidget extends StatelessWidget {
final TextEditingController chatTextFieldController = TextEditingController();
late final _focusNode = FocusNode(
onKey: _handleKeyPress,
);
KeyEventResult _handleKeyPress(FocusNode focusNode, RawKeyEvent event) {
// handles submit on enter
if (event.isKeyPressed(LogicalKeyboardKey.enter) && !event.isShiftPressed) {
_sendMessage();
// handled means that the event will not propagate
return KeyEventResult.handled;
}
// ignore every other keyboard event including SHIFT+ENTER
return KeyEventResult.ignored;
}
void _sendMessage() {
if (chatTextFieldController.text.trim().isNotEmpty) {
// Do something with your input text
print(chatTextFieldController.text.trim());
// bring focus back to the input field
Future.delayed(Duration.zero, () {
_focusNode.requestFocus();
chatTextFieldController.clear();
});
}
}
@override
Widget build(BuildContext context) {
return Container(
child: TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
textInputAction: TextInputAction.newline,
autofocus: true,
focusNode: _focusNode,
controller: chatTextFieldController,
decoration: const InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.fromLTRB(8, 0, 0, 0),
hintText: "Enter your message here",
hintStyle: TextStyle(color: Colors.black54),
),
),
);
}
}

主要有3个关键变化

  • keyboardType: TextInputType.multiline,
  • textInputAction: TextInputAction.newline,
  • 可监听键盘事件的FocusNode

对输入禁用Enter键,而在未按下ctrl键时发送它的最佳方法是直接通过输入上的focusNode,这样就不必删除额外的新行。

class _InputTextState extends State<InputText> {
late final _focusNode = FocusNode(onKey: handleKeyPress);

@override
Widget build(BuildContext context) {
return TextField(
focusNode: _focusNode,
);
}
KeyEventResult handleKeyPress(FocusNode focusNode, RawKeyEvent event) {
// handles submit on enter
if (kIsWeb &&
event.isKeyPressed(LogicalKeyboardKey.enter) &&
!event.isControlPressed &&
!event.isShiftPressed) {
widget.onSubmit();
// handled means that the event will not propagate
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
}
}

最新更新