如何立即切换焦点组(通过键盘)?

Mer*_*itt 3 desktop web flutter

当从一个焦点组遍历到下一个焦点组时(键盘上有选项卡),我希望焦点移动到下一组中的第一个字段,但它似乎没有关注任何内容 - 然后另一个选项卡移动到该组中。

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SizedBox(
          width: double.infinity,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              for (var i = 0; i < 2; i++)
                FocusableActionDetector(
                  onFocusChange: (focused) {
                    if (!focused) {
                      print('Have left focus group');
                    }
                  },
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      for (var i = 0; i < 3; i++)
                        SizedBox(
                          width: 150,
                          child: TextField(),
                        ),
                    ],
                  ),
                ),
            ],
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

飞镖板示例

我希望在第一组中的最后一个字段之后,按Tab应该立即将焦点移动到下一个焦点组中的第一个项目。

我已经尝试了各种方式FocusNodeFocusScope但是FocusScope.of(context).___我发现 Flutter 中的焦点管理有点令人困惑。

Bak*_*ker 6

前言:我不是这方面的专家Focus,我自己也觉得这很复杂。

\n

但我相信,下面的内容适用于您所追求的内容,从一列遍历到下一列,而不关注“不可见”项目。至少在移动设备上是这样。网络平台...这是一个完全不同的游戏(我怀疑它的工作原理是否相同)。

\n

我摆脱了FocusableActionDetector(它充当自身FocusNode)并将每个列包装在FocusTraversalGroup. 我相信 Flutter 会尽可能从 TraversalGroup 转向 TraversalGroup。

\n

包裹FocusScopeTraversalGroups 可防止“后退”按钮和任何其他可点击项目获得焦点(一旦FocusScope获得焦点)。

\n
class MyHomePage2 extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: SizedBox(\n          width: double.infinity,\n          child: FocusScope( // LIMIT FOCUS TO DESCENDANTS\n            child: Row(\n              mainAxisAlignment: MainAxisAlignment.spaceEvenly,\n              children: [\n                for (var i = 0; i < 2; i++)\n                  FocusTraversalGroup( // CREATE GROUPS HERE\n                    child: Column(\n                      mainAxisAlignment: MainAxisAlignment.center,\n                      children: [\n                        for (var i = 0; i < 3; i++)\n                          SizedBox(\n                            width: 150,\n                            child: TextField(),\n                          ),\n                      ],\n                    ),\n                  ),\n              ],\n            ),\n          ),\n        ),\n      ),\n    );\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

概括

\n

(据我所知,这是模糊的)

\n
    \n
  • FocusScope将节点遍历限制为其直接后代节点\n
      \n
    • 焦点不会从一个移动FocusScope到另一个FocusScope
    • \n
    • 要转到另一个,FocusScope用户需要手动/单击聚焦另一个FocusScope,或其后代节点必须requestFocus
    • \n
    • 使用FocusScope而不是FocusTraversalGroup上面的,会将节点遍历限制为 1 Column,以获得焦点的为准。当到达最后一个时,它不会从一个跳到Column下一个TextField
    • \n
    \n
  • \n
  • FocusTraversalGroup将后代收集到一个组中进行遍历\n
      \n
    • 但焦点离开这个组而转移到​​另一个组
    • \n
    • 当到达最后一个子节点并且另一个FocusTraversalGroup可用时跳转
    • \n
    • 可以调整组内的遍历顺序
    • \n
    \n
  • \n
\n

调试

\n

使用(随处可用的静态函数)转储焦点树debugDumpFocusTree有助于调试。

\n

有时我将其添加到 AppBar 中以便轻松按需访问:

\n
    return Scaffold(\n      appBar: AppBar(\n        title: Text('Focus Tab Page'),\n        actions: [\n          IconButton(icon: Icon(Icons.info_outline), onPressed: debugDumpFocusTree)\n        ],\n      ),\n
Run Code Online (Sandbox Code Playgroud)\n

我已复制到下面的相关部分。

\n
\xe2\x94\x94\xe2\x94\x80Child 2: FocusScopeNode#c83f0(_ModalScopeState<dynamic> Focus Scope [IN FOCUS PATH])\n  \xe2\x94\x82 context: FocusScope\n  \xe2\x94\x82 IN FOCUS PATH\n  \xe2\x94\x82 focusedChildren: FocusScopeNode#7d536([IN FOCUS PATH])\n  \xe2\x94\x82\n  \xe2\x94\x9c\xe2\x94\x80Child 1: FocusScopeNode#7d536([IN FOCUS PATH])\n  \xe2\x94\x82 \xe2\x94\x82 context: FocusScope\n  \xe2\x94\x82 \xe2\x94\x82 IN FOCUS PATH\n  \xe2\x94\x82 \xe2\x94\x82 focusedChildren: FocusNode#1b886([PRIMARY FOCUS]),\n  \xe2\x94\x82 \xe2\x94\x82   FocusNode#72c3b, FocusNode#34b25, FocusNode#3b410,\n  \xe2\x94\x82 \xe2\x94\x82   FocusNode#02fac, FocusNode#61cd5\n  \xe2\x94\x82 \xe2\x94\x82\n  \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80Child 1: FocusNode#1d51e(FocusTraversalGroup)\n  \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 context: Focus\n  \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 NOT FOCUSABLE\n  \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82\n  \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80Child 1: FocusNode#3b410\n  \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82   context: EditableText-[LabeledGlobalKey<EditableTextState>#70699]\n  \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82\n  \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80Child 2: FocusNode#34b25\n  \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82   context: EditableText-[LabeledGlobalKey<EditableTextState>#7c822]\n  \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82\n  \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80Child 3: FocusNode#72c3b\n  \xe2\x94\x82 \xe2\x94\x82     context: EditableText-[LabeledGlobalKey<EditableTextState>#f00bc]\n  \xe2\x94\x82 \xe2\x94\x82\n  \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80Child 2: FocusNode#bdb17(FocusTraversalGroup [IN FOCUS PATH])\n  \xe2\x94\x82   \xe2\x94\x82 context: Focus\n  \xe2\x94\x82   \xe2\x94\x82 NOT FOCUSABLE\n  \xe2\x94\x82   \xe2\x94\x82 IN FOCUS PATH\n  \xe2\x94\x82   \xe2\x94\x82\n  \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80Child 1: FocusNode#1b886([PRIMARY FOCUS])\n  \xe2\x94\x82   \xe2\x94\x82   context: EditableText-[LabeledGlobalKey<EditableTextState>#c5a56]\n  \xe2\x94\x82   \xe2\x94\x82   PRIMARY FOCUS\n  \xe2\x94\x82   \xe2\x94\x82\n  \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80Child 2: FocusNode#61cd5\n  \xe2\x94\x82   \xe2\x94\x82   context: EditableText-[LabeledGlobalKey<EditableTextState>#a4dd8]\n  \xe2\x94\x82   \xe2\x94\x82\n  \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80Child 3: FocusNode#02fac\n  \xe2\x94\x82       context: EditableText-[LabeledGlobalKey<EditableTextState>#fe12d]\n  \xe2\x94\x82\n  \xe2\x94\x9c\xe2\x94\x80Child 2: FocusNode#4886e\n  \xe2\x94\x82   context: Focus\n  \xe2\x94\x82\n  \xe2\x94\x94\xe2\x94\x80Child 3: FocusNode#9241b\n      context: Focus\n
Run Code Online (Sandbox Code Playgroud)\n

  • 完美的答案,使用 `debugDumpFocusTree` 的好处!“FocusTraversalGroup”主要是我所需要的,你帮助我理解了它如何更好地工作。此外,对于我的用例,我需要在聚焦时设置“TextField”的选择,因此我用带有“skipTraversal: true”的“Focus”包装 TextFields,并在“onFocusChange”内设置控制器选择。感谢您的出色回答,非常感谢!&lt;3 (2认同)