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

标签 flutter web desktop

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

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(),
                        ),
                    ],
                  ),
                ),
            ],
          ),
        ),
      ),
    );
  }
}
Dartpad example
我希望在第一组的最后一个字段之后按 Tab应立即将焦点移至下一个焦点组中的第一个项目。
我已经尝试了各种FocusNode , FocusScope , FocusScope.of(context).___ ,但是我发现 Flutter 中的焦点管理有点困惑。

最佳答案

前言:我不是Focus的专家我自己也觉得很复杂。
但我相信以下内容适用于您所追求的内容,从一列遍历到下一列,而不聚焦“不可见”的项目 .至少在移动设备上。网络平台......这是一个完全不同的球赛(我怀疑它的工作原理是一样的)。
我摆脱了FocusableActionDetector (它作为 FocusNode 本身)并将每个 Column 包裹在一个 FocusTraversalGroup 中.我相信 Flutter 会尽可能地从 TraversalGroup 转到 TraversalGroup。FocusScope包装 TraversalGroups 可防止后退按钮和任何其他可点击项目获得焦点(一旦 FocusScope 获得焦点)。

class MyHomePage2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SizedBox(
          width: double.infinity,
          child: FocusScope( // LIMIT FOCUS TO DESCENDANTS
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                for (var i = 0; i < 2; i++)
                  FocusTraversalGroup( // CREATE GROUPS HERE
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        for (var i = 0; i < 3; i++)
                          SizedBox(
                            width: 150,
                            child: TextField(),
                          ),
                      ],
                    ),
                  ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
概括
(据我所知,这是模糊的)
  • FocusScope限制节点遍历到它的直接后代节点
  • 焦点不会从一个遍历FocusScope到另一个 FocusScope
  • 去另一个FocusScope用户将需要手动/单击聚焦另一个 FocusScope ,或其后代节点必须requestFocus
  • 使用 FocusScope而不是 FocusTraversalGroup以上,将节点遍历限制为一个 Column ,以得到焦点为准。它不会从一个 Column 跳转到达最后一个时到下一个 TextField

  • FocusTraversalGroup将后代收集到一个组中进行遍历
  • 但重点离开这个组到另一个组
  • 在最后一个子节点和另一个 FocusTraversalGroup 时跳转有货
  • 可以调整其组内的遍历顺序


  • 调试
    使用 debugDumpFocusTree 转储焦点树(随处可用的静态函数)有助于调试。
    我有时会将它添加到 AppBar 以便于按需访问:
        return Scaffold(
          appBar: AppBar(
            title: Text('Focus Tab Page'),
            actions: [
              IconButton(icon: Icon(Icons.info_outline), onPressed: debugDumpFocusTree)
            ],
          ),
    
    我已复制到下面的相关部分。
    └─Child 2: FocusScopeNode#c83f0(_ModalScopeState<dynamic> Focus Scope [IN FOCUS PATH])
      │ context: FocusScope
      │ IN FOCUS PATH
      │ focusedChildren: FocusScopeNode#7d536([IN FOCUS PATH])
      │
      ├─Child 1: FocusScopeNode#7d536([IN FOCUS PATH])
      │ │ context: FocusScope
      │ │ IN FOCUS PATH
      │ │ focusedChildren: FocusNode#1b886([PRIMARY FOCUS]),
      │ │   FocusNode#72c3b, FocusNode#34b25, FocusNode#3b410,
      │ │   FocusNode#02fac, FocusNode#61cd5
      │ │
      │ ├─Child 1: FocusNode#1d51e(FocusTraversalGroup)
      │ │ │ context: Focus
      │ │ │ NOT FOCUSABLE
      │ │ │
      │ │ ├─Child 1: FocusNode#3b410
      │ │ │   context: EditableText-[LabeledGlobalKey<EditableTextState>#70699]
      │ │ │
      │ │ ├─Child 2: FocusNode#34b25
      │ │ │   context: EditableText-[LabeledGlobalKey<EditableTextState>#7c822]
      │ │ │
      │ │ └─Child 3: FocusNode#72c3b
      │ │     context: EditableText-[LabeledGlobalKey<EditableTextState>#f00bc]
      │ │
      │ └─Child 2: FocusNode#bdb17(FocusTraversalGroup [IN FOCUS PATH])
      │   │ context: Focus
      │   │ NOT FOCUSABLE
      │   │ IN FOCUS PATH
      │   │
      │   ├─Child 1: FocusNode#1b886([PRIMARY FOCUS])
      │   │   context: EditableText-[LabeledGlobalKey<EditableTextState>#c5a56]
      │   │   PRIMARY FOCUS
      │   │
      │   ├─Child 2: FocusNode#61cd5
      │   │   context: EditableText-[LabeledGlobalKey<EditableTextState>#a4dd8]
      │   │
      │   └─Child 3: FocusNode#02fac
      │       context: EditableText-[LabeledGlobalKey<EditableTextState>#fe12d]
      │
      ├─Child 2: FocusNode#4886e
      │   context: Focus
      │
      └─Child 3: FocusNode#9241b
          context: Focus
    

    关于flutter - 如何立即切换焦点组(通过键盘)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67808972/

    相关文章:

    android - 在 Flutter Form Widget 中动态添加字段

    java 。通过单击按钮绘制形状的问题

    desktop - 最好的开发机快捷方式管理工具?

    highcharts - 如何在 Flutter 应用中使用 HighCharts dart 库?

    dart - 如何将 Future<dynamic> 转换/转换为图像?

    php - 无法从 laravel 中的相关表中获取详细信息(使用 with)

    css - CSS 的 <span></span> 与 <span/> 的区别?

    python - flask 测试 : Test App Request?

    linux - 从终端 tty 到桌面 session 启动程序。

    android - 如何在 flutter 中创建 SharedPreferences 的单例类