🕌

【Flutterエラー】TextFormFieldのキーボードが勝手に閉じる問題と解決策

2025/03/06に公開

はじめに

Flutterアプリを開発していると、TextFormField をタップした際にキーボードがすぐに閉じてしまう問題に遭遇することがあります。

特に、HookWidget を使っている場合に GlobalKey<FormState> の管理方法に工夫が必要になるケースがあります。

本記事では、この問題の原因と解決策を簡単に説明します。

問題の発生例

以下のコードでは、HookWidget を使用し、GlobalKey<FormState> を変数として定義しています。

sample_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

class SampleScreen extends HookWidget {
  
  Widget build(BuildContext context) {
    final formKey = GlobalKey<FormState>(); // ここが問題
    final textController = useTextEditingController();

    return Scaffold(
      appBar: AppBar(title: Text('キーボードが閉じる問題')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: formKey.value,
          child: Column(
            children: [
              TextFormField(
                controller: textController,
                decoration: InputDecoration(labelText: '入力してください'),
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  if (formKey.value.currentState?.validate() ?? false) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('入力が検証されました')),
                    );
                  }
                },
                child: Text('検証'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

なぜこのコードでキーボードが閉じてしまうのか?

  • GlobalKey<FormState>() を単に変数として管理しているため、build のたびに GlobalKey が再生成される可能性がある。
  • GlobalKey が変更されると Form が再構築され、フォーカスがリセットされてしまう。

解決策

useMemoized を使い、GlobalKey<FormState>build のたびに再生成しないようにします。

修正後のコード

sample_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

class SampleScreen extends HookWidget {
  
  Widget build(BuildContext context) {
    final formKey = useMemoized(() => GlobalKey<FormState>());
    final textController = useTextEditingController();

    return Scaffold(
      appBar: AppBar(title: Text('キーボードが閉じる問題(解決)')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: formKey,
          child: Column(
            children: [
              TextFormField(
                controller: textController,
                decoration: InputDecoration(labelText: '入力してください'),
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  if (formKey.currentState?.validate() ?? false) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('入力が検証されました')),
                    );
                  }
                },
                child: Text('検証'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

変更点

  • 変数やuseState で管理する代わりに useMemoized を使用し、GlobalKey<FormState> を再生成しないようにした。
  • これにより、FormGlobalKey が変わらなくなり、キーボードが勝手に閉じる問題が解消される。

まとめ

HookWidget を使用する際に GlobalKey<FormState> を 変数やuseState で管理すると、キーボードが勝手に閉じる原因になります。useMemoized を使うことで、GlobalKey の再生成を防ぎ、安定したフォームの動作を実現できます。

個人的には、今までuseMemoizedを使う機会が少なかったので理解する良い機会となりました。
参考になると嬉しいです!読んでいただき、ありがとうございます!

Discussion