You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在textInputAction为Done的Flutter多行TextField中换行?

解决多行TextField同时支持换行输入与Done提交的问题

针对右侧多行TextField无法换行的问题,我们可以通过调整配置,让它既能支持换行输入,又能保留Done按钮触发onSubmitted方法。

修改方案

核心调整点:

  • 将keyboardType设置为TextInputType.multiline,让虚拟键盘显示换行键,允许输入换行
  • 保留textInputAction: TextInputAction.done,让键盘显示Done按钮,点击时触发提交
  • 兼容物理键盘:通过监听按键事件,区分普通Enter(换行)和组合键(提交)

修改后的代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Flutter TextField Multiple Lines'),
        ),
        body: const MyStatefulWidget());
  }
}

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({super.key});

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  late TextEditingController _controllerEnter;
  late TextEditingController _controllerDone;

  @override
  void initState() {
    super.initState();
    _controllerEnter = TextEditingController();
    _controllerDone = TextEditingController();
  }

  @override
  void dispose() {
    _controllerEnter.dispose();
    _controllerDone.dispose();
    super.dispose();
  }

  // 处理物理键盘按键事件
  void _handleKeyEvent(RawKeyEvent event) {
    if (event is RawKeyDownEvent) {
      // 物理键盘按下Ctrl+Enter时触发提交
      if (event.isControlPressed && event.logicalKey == LogicalKeyboardKey.enter) {
        FocusScope.of(context).unfocus();
        _onSubmitted(_controllerDone.text);
      }
      // 普通Enter键插入换行
      else if (event.logicalKey == LogicalKeyboardKey.enter) {
        final text = _controllerDone.text;
        final selection = _controllerDone.selection;
        _controllerDone.text = '${text.substring(0, selection.start)}\n${text.substring(selection.end)}';
        _controllerDone.selection = selection.copyWith(
          baseOffset: selection.start + 1,
          extentOffset: selection.start + 1,
        );
      }
    }
  }

  void _onSubmitted(String value) {
    debugPrint('\n*** onSubmitted: $value ***\n');
  }

  @override
  Widget build(BuildContext context) {
    return Center(
        child: Padding(
      padding: const EdgeInsets.all(20.0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          SizedBox(
            width: 150,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text(
                  'Multiline TextField Enter',
                  style: TextStyle(fontSize: 20),
                ),
                Focus(
                  child: TextField(
                    style: const TextStyle(fontSize: 20),
                    maxLines: 3,
                    controller: _controllerEnter,
                    onSubmitted: (String value) {
                      // 多行默认Enter键是换行,不会触发onSubmitted
                      debugPrint('\n*** onSubmitted: $value ***\n');
                    },
                  ),
                  onFocusChange: (value) {
                    if (!value) {
                      debugPrint('\n*** onFocusChange: ${_controllerEnter.text} ***\n');
                    }
                  },
                ),
              ],
            ),
          ),
          const SizedBox(width: 25),
          SizedBox(
            width: 150,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text(
                  'Multiline TextField Done',
                  style: TextStyle(fontSize: 20),
                ),
                // 添加RawKeyboardListener处理物理键盘
                RawKeyboardListener(
                  focusNode: FocusNode(),
                  onKey: _handleKeyEvent,
                  child: TextField(
                    style: const TextStyle(fontSize: 20),
                    maxLines: 3,
                    // 设置为multiline类型,启用换行输入
                    keyboardType: TextInputType.multiline,
                    textInputAction: TextInputAction.done,
                    controller: _controllerDone,
                    onSubmitted: _onSubmitted,
                    // 可选:调整换行行为
                    textCapitalization: TextCapitalization.sentences,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    ));
  }
}

关键说明

  1. 虚拟键盘适配:设置keyboardType: TextInputType.multiline后,虚拟键盘会同时显示换行键和Done键,用户点击换行键即可输入换行,点击Done键触发onSubmitted。
  2. 物理键盘适配:通过RawKeyboardListener监听物理键盘事件,普通Enter键插入换行,Ctrl+Enter组合键触发提交,覆盖不同输入场景。
  3. 原有功能保留:保留textInputAction: TextInputAction.done,确保Done按钮的提交逻辑正常生效。

内容的提问来源于stack exchange,提问作者Jean-Pierre Schnyder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 21:10:19