【Flutter】TextFieldをキーボードにてフォーカスを変える方法〔nextとdone〕

Flutter
 

FlutterのTextFieldを複数並べたときに、キーボード上の「次へ・確定」ボタンを押下するだけで
次のTextFieldや画面遷移をさせる方法を紹介します。

実装イメージ

以下の操作手順をしたものをMovieにて表示します。

  1. 初期画面にてListを描画したものが表示
  2. 右下の「+」ボタンをタップするとListを追加する画面に遷移
  3. TextAをタップしてキーボードから文字を入力し、右下の「next」をタップ
  4. TextBにフォーカスが変わる。再び文字を入力して、右下の「done」をタップ
  5. 画面が一つ戻り、ListにTextAとTextBに入力した文字が追加されてListが表示

実装ソース

以下のようなWidgetを作成することで実装できます。

ソース自体は少し長いですが、下記に関するソースに関連する部分は赤と青でハイライトしています。
(下の方にいます!!笑)

  • nextをタップして、次のTextFieldに遷移
  • doneをタップして、前画面に遷移

前者は
TextFieldのフィールドの一つであるtextInputActionを定義してあげることで、
例えばColumnの次に定義されているTextFieldにフォーカスさせることができます。

後者は、
TextFieldのフィールドの一つであるonSubmittedを定義してあげることで、
doneをタップした後の動作を指定してあげています。
(今回ならばNavigator.of(context).pop([_text1, _text2])というように
画面のテキスト部分に入力された値を保持して前Widgetに渡しています。)

class TodoListPage extends StatefulWidget {
  const TodoListPage({super.key});

  @override
  State<TodoListPage> createState() => _TodoListPageState();
}

List<String> weekly_todo = <String>[
  'one',
  'two',
  'three',
  'four',
  'five',
];

class _TodoListPageState extends State<TodoListPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
        itemBuilder: ((BuildContext context, int index) {
          return Container(
            height: 60,
            child: Card(
              child: ListTile(
                title: Text(weekly_todo[index]),
                leading: Icon(
                  IconData(0xef53, fontFamily: 'MaterialIcons'),
                  size: 40.0,
                ),
              ),
            ),
          );
        }),
        itemCount: weekly_todo.length,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final List newTodoText = await Navigator.of(context).push(
            MaterialPageRoute(
              builder: ((context) {
                return TodoAddPage();
              }),
            ),
          );
          if (newTodoText != null) {
            setState(() {
              // リスト追加
              weekly_todo.add(newTodoText[0]);
              weekly_todo.add(newTodoText[1]);
            });
          }
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

class TodoAddPage extends StatefulWidget {
  const TodoAddPage({
    Key? key,
  }) : super(key: key);

  @override
  State<TodoAddPage> createState() => _TodoAddPageState();
}

class _TodoAddPageState extends State<TodoAddPage> {
  String _text1 = '';
  String _text2 = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: [
            TextField(
              onChanged: ((String value) {
                setState(() {
                  _text1 = value;
                });
              }),
              decoration: InputDecoration(hintText: 'TextA'),
              textInputAction: TextInputAction.next,
            ),
            TextField(
              onChanged: ((String value) {
                setState(() {
                  _text2 = value;
                });
              }),
              onSubmitted: (v) {
                Navigator.of(context).pop([_text1, _text2]);
              },
              decoration: InputDecoration(hintText: 'TextB'),
            ),
          ],
        ),
      ),
    );
  }
}

コメント

タイトルとURLをコピーしました