Текстовое поле Flutter — как поддерживать отправку при _и_ новой строке при

#flutter #flutter-layout #flutter-web

#flutter #flutter-макет #flutter-web

Вопрос:

Я работаю над веб-приложением Flutter, которое включает чат.

Я хотел бы включить обычную функцию ввода, в которой пользователи могут вводить текст и отправлять его в поток чата. Стандартная функция приложений для чатов в наши дни — это send включение <ENTER> и выполнение разрыва строки <SHIFT-ENTER> или некоторая вариация этого.

В настоящее время я смог выполнить только одну из этих функций одновременно. Если вы установите значение TextField ‘s keyboardType в TextInputType.multiline значение then <ENTER> и <SHIFT-ENTER> всегда выполняете разрыв строки, похоже, нет способа переопределить это поведение.

Если вместо TextField этого TextInputType.text вы можете захватить <ENTER> и отправить, но попытка захвата <SHIFT-ENTER> для добавления разрыва строки не сработала. Я пытался вручную захватить нажатие клавиши с помощью onKey обработчика и вставить n в controller.text , но, похоже, это TextInputType.text вообще не предназначено для многострочного, поэтому оно не работает хорошо.

Просто интересно, сталкивались ли с этим какие-либо другие разработчики или предлагали какие-либо подходящие решения. В идеале решение также будет работать на Android / ios. Что касается меня, я решил TextInputType.text пока отказаться от многострочной функциональности.

Спасибо

Ответ №1:

Как бы то ни было, я смог придумать разумное решение, которое я опубликую ниже на случай, если кто-нибудь столкнется с этим самостоятельно.

Я завернул текстовое поле в прослушиватель клавиатуры, который вызывает мою onSend функцию, когда видит, что это an <Enter> . Я пробовал это раньше, но, думаю, раньше мне не хватало приведения RawKeyEventDataWeb , которое позволяло мне захватывать isShiftPressed новые строки <SHFT-ENTER> без принудительной отправки. К сожалению, мне пришлось добавить немного хакерского кода, чтобы удалить n то, что добавляется при нажатии enter, но это небольшая цена за функциональный современный обмен сообщениями.

 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 amp;amp; event.data is RawKeyEventDataWeb) {
  var data = event.data as RawKeyEventDataWeb;
  if (data.code == "Enter" amp;amp; !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();
  }
}
}
 

Ответ №2:

Этого можно добиться, добавив a FocusNode в TextField . Поместите узел фокусировки в состояние вашего виджета.

 late final _focusNode = FocusNode(
  onKey: (FocusNode node, RawKeyEvent evt) {
    if (!evt.isShiftPressed amp;amp; 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,
)
 

Комментарии:

1. очень рабочий ответ без какого-либо дополнительного виджета

Ответ №3:

Лучший способ 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 amp;amp;
        event.isKeyPressed(LogicalKeyboardKey.enter) amp;amp;
        !event.isControlPressed amp;amp;
        !event.isShiftPressed) {
      widget.onSubmit();
    // handled means that the event will not propagate
      return KeyEventResult.handled;
    }
    return KeyEventResult.ignored;
  }
}