👓
Flutter TextFieldが勝手にフォーカスされる問題
問題の概要
症状: Drawerを開いた瞬間に、TextFieldが自動的にフォーカスを獲得してキーボードが意図せず表示される
※Drawerに限らず、他のアクションでも自動的にフォーカスされる。
再現手順:
- TextFieldをタップしてキーボードを表示
- キーボードの閉じるボタンでキーボードを閉じる
- Drawerを開く
- 意図しない結果: TextFieldが再度フォーカスを獲得し、キーボードが表示される
コード
KeyboardToolbar(
onDismiss: () { //キーボードの閉じるボタンを押すた時に時の処理
_isKeyboardVisible = false;
FocusScope.of(context).unfocus();
}
)
根本原因の解明
真の敵:Flutter のFocusScope/FocusManager履歴機能
Flutterのフォーカス管理システムには「履歴機能」があり、以前フォーカスを持っていたウィジェットを記憶している。Drawer等のモーダル遷移後、システムが自動的に以前のフォーカス状態を復元しようとする。キーボード操作などアクセシビリティの一貫性のためだと思われる。
Within a scope, the most recent nodes to have focus are remembered, and if a node is focused and then removed, the original node receives focus again.
FocusScopeNode class
// 問題のメカニズム
// 1. TextFieldがフォーカスを持つ → FocusManagerが履歴に記録
// 2. unfocus()でフォーカスを外す → しかし履歴は残る
// 3. Drawerを開く → モーダル遷移が発生
// 4. システムが履歴からTextFieldのフォーカスを復元 ← ここが問題!
フォーカス履歴リセット作戦
解決策
KeyboardToolbar(
onDismiss: () {
_isKeyboardVisible = false;
FocusScope.of(context).requestFocus(FocusNode()); //追加!
FocusScope.of(context).unfocus();
}
)
解決メカニズム
// 新しいFocusNodeにフォーカスを移す
FocusScope.of(context).requestFocus(FocusNode());
// 効果:
// 1. 以前のTextField履歴が上書きされる
// 2. Drawer開閉時にTextFieldフォーカス復元が発生しない
解決🎊
Discussion