如何判断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
相关产品推荐
相关产品推荐

