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

如何判断Flutter Widget是否会获得焦点 能否从子组件侧获取previouslyFocusedChild信息

Flutter获取previouslyFocusedChild并高亮的实现方案

该需求完全可以实现,Flutter焦点系统本身暴露了对应的状态接口,你可以通过以下两种主流方案实现:

方案1:通过当前上下文的FocusScope直接读取

FocusScopeNode中天然存储了历史焦点的相关状态,你可以直接从组件所属的焦点域中获取目标属性:

  • 调用FocusScope.of(context)拿到当前组件树对应的焦点域节点
  • 该节点的previouslyFocusedChild属性就是配置previouslyFocusedChild策略后,调用unfocus会自动获取焦点的历史子节点
  • 给焦点域节点添加addListener监听焦点变更事件,每次焦点变化时比对当前子组件的FocusNode是否与previouslyFocusedChild相等,相等就触发高亮逻辑

参考代码示例:

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

  @override
  State<HighlightPrevFocusWidget> createState() => _HighlightPrevFocusWidgetState();
}

class _HighlightPrevFocusWidgetState extends State<HighlightPrevFocusWidget> {
  late final FocusNode myFocusNode;
  bool _isPrevFocused = false;

  @override
  void initState() {
    super.initState();
    myFocusNode = FocusNode(debugLabel: '需要识别的子组件焦点');
    // 页面渲染完成后再获取焦点域,避免上下文未挂载报错
    WidgetsBinding.instance.addPostFrameCallback((_) {
      final focusScope = FocusScope.of(context);
      focusScope.addListener(_checkPrevFocus);
    });
  }

  void _checkPrevFocus() {
    final focusScope = FocusScope.of(context);
    final currentIsPrev = focusScope.previouslyFocusedChild == myFocusNode;
    if (currentIsPrev != _isPrevFocused) {
      setState(() => _isPrevFocused = currentIsPrev);
    }
  }

  @override
  void dispose() {
    // 销毁时移除监听器,避免内存泄漏
    FocusScope.of(context).removeListener(_checkPrevFocus);
    myFocusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      focusNode: myFocusNode,
      decoration: InputDecoration(
        // 根据状态调整边框颜色实现高亮
        border: const OutlineInputBorder(),
        enabledBorder: _isPrevFocused 
            ? const OutlineInputBorder(borderSide: BorderSide(color: Colors.red, width: 2))
            : const OutlineInputBorder(),
      ),
    );
  }
}

方案2:全局缓存历史焦点节点(跨焦点域场景适用)

如果你的需求需要跨多个焦点域识别历史焦点节点,可以自己做全局的焦点状态缓存:

  • 通过WidgetsBinding.instance.addObserver监听全局焦点变化事件
  • 每次焦点变更时,将当前失去焦点的节点存储到全局变量中
  • 所有子组件都可以直接读取该全局变量,和自身的FocusNode比对即可

注意点

  • 如果你是主动调用requestFocus切换焦点,而非通过unfocus触发焦点回退,previouslyFocusedChild不会自动更新,这种场景你需要自己手动缓存历史焦点节点
  • 所有添加的监听器一定要在组件销毁时移除,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 04:36:03