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

Flutter:实现TextFormField失焦时从开头显示溢出文本

问题:TextField失焦时让文本自动滚动到开头位置

在TextField中输入长文本后切换到其他组件(如另一个TextField),失焦的TextField会停留在文本末尾位置,希望实现失焦时文本自动滚动到开头显示。

当前状态

邮箱输入框失焦状态
当前状态

期望效果

期望效果

尝试过的方法

曾尝试通过以下代码调整选中位置,但仅在再次聚焦组件时生效,无法在失焦瞬间达到预期:

textEditingController.selection = TextSelection.collapsed(offset: 0);

完整代码(更新)

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  TextEditingController textEditingController1 = TextEditingController();
  TextEditingController textEditingController2 = TextEditingController();
  FocusNode focusNode1 = FocusNode();
  FocusNode focusNode2 = FocusNode();

  @override
  void dispose() {
    textEditingController1.dispose();
    textEditingController2.dispose();
    focusNode1.dispose();
    focusNode2.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Column(
        children: [
          SizedBox(
            width: 100,
            child: TextField(
              focusNode: focusNode1,
              onEditingComplete: () {
                textEditingController1.selection = TextSelection.collapsed(offset: 0);
                focusNode1.unfocus();
                FocusScope.of(context).requestFocus(focusNode2);
              },
              controller: textEditingController1,
              textInputAction: TextInputAction.next,
            ),
          ),
          SizedBox(
            width: 100,
            child: TextField(
              focusNode: focusNode2,
              onEditingComplete: () {
                textEditingController2.selection = TextSelection.collapsed(offset: 0);
                focusNode2.unfocus();
                FocusScope.of(context).requestFocus(focusNode1);
              },
              controller: textEditingController2,
              textInputAction: TextInputAction.next,
            ),
          ),
        ],
      ),
    );
  }
}

解决方案

问题出在原代码的执行顺序:在onEditingComplete中先设置选中位置再失焦,Flutter的UI更新逻辑会覆盖这个选中状态。正确的做法是通过FocusNode的焦点监听,结合addPostFrameCallback确保UI绘制完成后调整选中位置。

修改步骤:

  1. 在initState中给两个FocusNode添加焦点变化监听,失焦时调整文本选中位置:
@override
void initState() {
  super.initState();
  
  focusNode1.addListener(() {
    if (!focusNode1.hasFocus) {
      // 等待当前帧绘制完成后执行,确保选中状态生效
      WidgetsBinding.instance.addPostFrameCallback((_) {
        textEditingController1.selection = const TextSelection.collapsed(offset: 0);
      });
    }
  });

  focusNode2.addListener(() {
    if (!focusNode2.hasFocus) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        textEditingController2.selection = const TextSelection.collapsed(offset: 0);
      });
    }
  });
}
  1. 简化onEditingComplete方法,只处理焦点切换即可:
// 第一个TextField的onEditingComplete
onEditingComplete: () {
  FocusScope.of(context).requestFocus(focusNode2);
},

// 第二个TextField的onEditingComplete
onEditingComplete: () {
  FocusScope.of(context).requestFocus(focusNode1);
},

这样修改后,无论通过点击下一个输入框还是其他方式让TextField失焦,文本都会自动滚动到开头位置,符合预期效果。

内容的提问来源于stack exchange,提问作者Yassir Rabiea

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 03:07:50