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

Flutter如何检测TextField编辑取消/键盘收起/失去焦点并处理未保存修改

问题根源

你遇到的状态不一致核心来自两个问题:

  1. 你在build方法中每次都新建TextEditingController,即使Cubit状态更新也不会同步到正在编辑的输入框
  2. 原生TextField没有提供编辑中断(失去焦点、收起键盘)的回调,仅靠onSubmitted只能覆盖点击键盘完成的场景

解决方案

通过FocusNode监听输入框的焦点状态,当输入框失去焦点时就触发你需要的自定义逻辑(自动保存/回退原值均可),同时把TextEditingController移到State中维护,不要在build里重复创建。

修改后完整代码

testpage.dart

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import 'some_cubit.dart';

class TestPage extends StatefulWidget {
  const TestPage({Key? key}) : super(key: key);

  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage> {
  // 提前定义控制器和焦点节点
  late final TextEditingController _minController;
  late final TextEditingController _maxController;
  late final FocusNode _minFocusNode;
  late final FocusNode _maxFocusNode;

  @override
  void initState() {
    super.initState();
    _minController = TextEditingController();
    _maxController = TextEditingController();
    _minFocusNode = FocusNode();
    _maxFocusNode = FocusNode();

    // 监听最小值输入框焦点变化
    _minFocusNode.addListener(() {
      if (!_minFocusNode.hasFocus) {
        // 失去焦点时触发逻辑,这里示例为自动保存,要回退的话直接写_minController.text = context.read<SomeCubit>().state.min.toString()即可
        context.read<SomeCubit>().updateMin(_minController.text);
      }
    });

    // 监听最大值输入框焦点变化
    _maxFocusNode.addListener(() {
      if (!_maxFocusNode.hasFocus) {
        context.read<SomeCubit>().updateMax(_maxController.text);
      }
    });
  }

  @override
  void dispose() {
    // 记得销毁资源
    _minController.dispose();
    _maxController.dispose();
    _minFocusNode.dispose();
    _maxFocusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Test')),
      body: BlocProvider(
        create: (context) => SomeCubit(),
        child: BlocListener<SomeCubit, SomeState>(
          // 监听Cubit状态变化,同步更新输入框内容
          listener: (context, state) {
            _minController.text = state.min.toString();
            _maxController.text = state.max.toString();
          },
          child: Column(
            children: [
              Flexible(
                child: TextField(
                  controller: _minController,
                  focusNode: _minFocusNode,
                  keyboardType: TextInputType.number,
                  onSubmitted: (s) {
                    context.read<SomeCubit>().updateMin(s);
                    // 提交后可以自动清焦点,也可以按需保留
                    _minFocusNode.unfocus();
                  },
                ),
              ),
              Flexible(
                child: TextField(
                  controller: _maxController,
                  focusNode: _maxFocusNode,
                  keyboardType: TextInputType.number,
                  onSubmitted: (s) {
                    context.read<SomeCubit>().updateMax(s);
                    _maxFocusNode.unfocus();
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

some_cubit.dart无需修改,和你原有代码一致即可。

可选逻辑实现

如果你需要在用户中断编辑时回退到原始值,只需要把焦点失去回调里的保存逻辑替换为重置控制器内容即可:

// 示例:失去焦点回退原值
_minFocusNode.addListener(() {
  if (!_minFocusNode.hasFocus) {
    final currentMin = context.read<SomeCubit>().state.min.toString();
    if (_minController.text != currentMin) {
      _minController.text = currentMin;
    }
  }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 05:45:08