Flutter中的Tab顺序

7
在我的Windows应用程序中(界面看起来像这样:https://istack.dev59.com/SibAC.webp),当我专注于输入框1并按下键盘上的Tab键时,主要焦点将转移到输入框3。有没有办法重新排列我的焦点顺序:输入框1->输入框2->输入框3->输入框4->输入框5。
注意:这不是flutter文档示例中的选项卡/标签控制器。
这是我的代码:
3个文件在同一根目录下:
main.dart
import 'package:flutter/material.dart';
import 'tab1.dart';
import 'tab2.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tab oder',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Tab order'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _controller = TextEditingController();
  final FocusNode _focusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Form(
        key: GlobalKey<FormState>(),
        onChanged: () {
          Form.of(primaryFocus!.context!)!.save();
        },
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            Container(
              constraints: const BoxConstraints.tightFor(width: 200.0, height: 200.0),
              child: TextFormField(
                controller: _controller,
                focusNode: _focusNode,
                decoration: const InputDecoration(
                  filled: true,
                  fillColor: Colors.yellow,
                ),
              ),
            ),
            const SizedBox(width: 150.0),
            Column(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                Container(
                  constraints: const BoxConstraints.tightFor(width: 200.0, height: 120.0),
                  child: Tab1(),
                ),
                Container(
                  constraints: const BoxConstraints.tightFor(width: 200.0, height: 120.0),
                  child: Tab2(),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

tab1.dart

import 'package:flutter/material.dart';

class Tab1 extends StatefulWidget {
  @override
  _Tab1State createState() => _Tab1State();
}

class _Tab1State extends State<Tab1> {
  final TextEditingController _controller1 = TextEditingController();
  final TextEditingController _controller2 = TextEditingController();
  final FocusNode _focusNode1 = FocusNode();
  final FocusNode _focusNode2 = FocusNode();

  @override
  build(BuildContext context) {
    return Column(
      children: [
        TextFormField(
          controller: _controller1,
          focusNode: _focusNode1,
          decoration: const InputDecoration(
            filled: true,
            fillColor: Colors.greenAccent,
          ),
        ),
        TextFormField(
          controller: _controller2,
          focusNode: _focusNode2,
          decoration: const InputDecoration(
            filled: true,
            fillColor: Colors.greenAccent,
          ),
        ),
      ],
    );
  }
}

tab2.dart

import 'package:flutter/material.dart';

class Tab2 extends StatefulWidget {
  @override
  _Tab2State createState() => _Tab2State();
}

class _Tab2State extends State<Tab2> {
  final TextEditingController _controller1 = TextEditingController();
  final TextEditingController _controller2 = TextEditingController();
  final FocusNode _focusNode1 = FocusNode();
  final FocusNode _focusNode2 = FocusNode();

  @override
  build(BuildContext context) {
    return Column(
      children: [
        TextFormField(
          controller: _controller1,
          focusNode: _focusNode1,
          decoration: const InputDecoration(
            filled: true,
            fillColor: Colors.greenAccent,
          ),
        ),
        TextFormField(
          controller: _controller2,
          focusNode: _focusNode2,
          decoration: const InputDecoration(
            filled: true,
            fillColor: Colors.greenAccent,
          ),
        ),
      ],
    );
  }
}

我是否可以切换选项卡1和选项卡2的显示(显示选项卡1隐藏选项卡2,或显示选项卡2隐藏选项卡1)? - TienVD
1
感谢提供易于复现的示例,这使得回答变得轻而易举。 - croxx5f
1个回答

10
通过使用 FocusTraversalGroup,您可以实现想要的行为,该小部件可以让您指定遍历顺序。
该小部件需要一个遍历策略作为参数,我使用了 OrderedTraversalPolicy,但还有其他策略,例如: WidgetOrderTraversalPolicy:依赖于小部件创建顺序来描述遍历顺序的策略。 ReadingOrderTraversalPolicy:根据当前 Directionality 的自然“阅读顺序”来描述顺序的策略。 NumericFocusOrder:分配数字遍历顺序的焦点顺序。 LexicalFocusOrder:分配基于字符串的词汇遍历顺序的焦点顺序。
此外,有一个关于构建自适应应用程序非常有趣的部分,其中包含不同平台上焦点和遍历顺序的一部分内容,您可以在这里查看
class Tab1 extends StatefulWidget {
  @override
  _Tab1State createState() => _Tab1State();
}

class _Tab1State extends State<Tab1> {
  final TextEditingController _controller1 = TextEditingController();
  final TextEditingController _controller2 = TextEditingController();
  final FocusNode _focusNode1 = FocusNode();
  final FocusNode _focusNode2 = FocusNode();

  @override
  build(BuildContext context) {
    return FocusTraversalGroup(
      policy: OrderedTraversalPolicy(),

如果您需要更改其他分组(例如 tab2)的遍历顺序,只需将它们包装在另一个 FocusTraversalGroup 中,并指定您想要它们遵循的策略。

请问您能否详细说明一下包括文本字段的上述示例?目前我正在尝试将文本字段放在FocusTraversalGroup下的列子元素中,但是没有任何反应。但问题是即使尝试使用Tab键改变焦点,仍然无法正常工作。 - gautam singh rathore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接