Tab order in flutter

233

You can achieve the behavior you want via a FocusTraversalGroup, with this widget you specify the order in which you want the traversal to be performed.

This widgets takes a traversal policy as a parameter, I used a OrderedTraversalPolicy, but there are others like:

WidgetOrderTraversalPolicy, a policy that relies on the widget creation order to describe the order of traversal.

ReadingOrderTraversalPolicy, a policy that describes the order as the natural "reading order" for the current Directionality.

NumericFocusOrder, a focus order that assigns a numeric traversal order.

LexicalFocusOrder a focus order that assigns a string-based lexical traversal orde.

Also there is an really interesting section about building adatpive apps in which focus and traversal order in different platforms is part of, you can check it out here

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(),

If you need to change the traversal order of other groups(like tab2) simply wrap them in another FocusTraversalGroup and specify the policy you want them to follow.

Share:
233
TienVD
Author by

TienVD

Updated on December 01, 2022

Comments

  • TienVD
    TienVD over 1 year

    On my Windows App ( The interface looks like this: https://i.stack.imgur.com/SibAC.png )

    When I focused to Input-1, and I press Tab key on keyboard, the primary focus will focus to Input-3. Is there any way to re-arrange my focus order: Input-1 -> Input-2 -> Input-3 -> Input-4 -> Input-5.

    Attention: This is not Tab bar/tab controller in flutter's docs example.

    This is my code:

    3 files is in same root

    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,
              ),
            ),
          ],
        );
      }
    }