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

Flutter 3.10中RawKeyboardListener修改TextField值崩溃问题求助

解决Flutter 3.10中RawKeyboardListener修改TextField值崩溃的问题

问题原因

Flutter 3.10对焦点管理和键盘事件处理逻辑做了优化,原代码存在两个核心问题:

  • RawKeyboardListener使用了独立的FocusNode,未与TextField的焦点关联,导致键盘事件处理时机与TextField内部状态更新冲突
  • 在键盘事件回调中直接同步修改_controller.text,会打断TextField的内部状态流转,引发崩溃

修复方案

  1. 共享焦点节点:让RawKeyboardListener与TextField使用同一个FocusNode,确保事件监听的是TextField的焦点状态
  2. 异步更新控制器:使用WidgetsBinding.instance.addPostFrameCallback延迟更新控制器内容,避免与当前帧的UI更新冲突
  3. 正确处理事件传递:在键盘事件处理后返回KeyEventResult.handled,阻止事件继续向上传递

修改后的完整代码

import 'dart:math';

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: 'TextField Arrow Keys Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('TextField Arrow Keys Demo'),
        ),
        body: const Center(
          child: MyHomePage(),
        ),
      ),
    );
  }
}

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

  @override
  State<StatefulWidget> createState() => _MyHomePage();
}

class _MyHomePage extends State<MyHomePage> {
  final TextEditingController _controller = TextEditingController();
  final FocusNode _focusNode = FocusNode(); // 共享的焦点节点
  final List<String> menuList = ['apple', 'banana', 'cat'];
  int menuIdx = 0;

  @override
  void initState() {
    super.initState();
    // 初始化TextField默认值
    _controller.text = menuList[menuIdx];
  }

  @override
  void dispose() {
    _controller.dispose();
    _focusNode.dispose(); // 释放焦点节点
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        SizedBox(
          width: 150,
          child: RawKeyboardListener(
            focusNode: _focusNode, // 使用共享的焦点节点
            onKey: (event) {
              if (event is RawKeyDownEvent) {
                if (event.logicalKey == LogicalKeyboardKey.arrowUp ||
                    event.logicalKey == LogicalKeyboardKey.arrowDown) {
                  setState(() {
                    if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
                      menuIdx = max(menuIdx - 1, 0);
                    } else {
                      menuIdx = min(menuIdx + 1, menuList.length - 1);
                    }
                  });
                  // 延迟更新控制器,避免帧内状态冲突
                  WidgetsBinding.instance.addPostFrameCallback((_) {
                    _controller.value = TextEditingValue(
                      text: menuList[menuIdx],
                      selection: TextSelection.collapsed(offset: menuList[menuIdx].length),
                    );
                  });
                  // 阻止事件继续传递
                  return KeyEventResult.handled;
                }
              }
              return KeyEventResult.ignored;
            },
            child: TextField(
              controller: _controller,
              focusNode: _focusNode, // 绑定同一个焦点节点
            ),
          ),
        ),
        const SizedBox(height: 20),
        ElevatedButton(
          onPressed: () {},
          child: const Text('Button 1'),
          focusNode: FocusNode(
            onKeyEvent: (node, event) {
              return KeyEventResult.handled;
            },
          ),
        ),
        const SizedBox(height: 10),
        ElevatedButton(
          onPressed: () {},
          child: const Text('Button 2'),
          focusNode: FocusNode(
            onKeyEvent: (node, event) {
              return KeyEventResult.handled;
            },
          ),
        ),
      ],
    );
  }
}

额外说明

  • 使用TextEditingValue赋值比直接修改text更安全,能同时控制文本内容和光标位置
  • 记得在dispose中释放FocusNode和TextEditingController,避免内存泄漏
  • 按钮的FocusNode处理保持不变,防止箭头键触发按钮焦点切换

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 06:20:38