Flutter:release modeだと、アプリ起動時に、TextFieldがフォーカスされていても、キーボードが出現しない

スポンサーリンク

2022/4/14〜15 Flutter エラー・バグ日記 

ここ数日、相当苦しんだ結果、ようやく解決したので記録。

 

アプリ起動と同時にすぐ書き込めるよう、TextFieldの「autofocus」を「true」にしていたが、Flutterをアップグレードしたためか、以前は問題なくできていた、アプリ起動と同時にキーボードを出す処理ができなくなっていた。

 

本記事はライトな日記思考で書いているので、詳細説明はしておらず、基本、テキストのみで画像とかは載せておりません。。m(_ _)m

解説記事ではないため、解決していない内容や、その時々の間違った解釈を述べてしまっている可能性が大いにありますので、何卒、ご了承ください。

 

TextFieldはフォーカスされており、カーソルは点滅しているが、なぜかキーボードが出てこない。

 

この状態で、TextField内を1回タップすれば出てくる。

 

また、別画面にいったん遷移してから戻ってきた場合も、特にタップせずともキーボードが出てくる。

 

この現象は、release modeでだけ発生する。debug modeだと、ちゃんとキーボードが出る。逆であれば問題ないが、release modeで発生するとなると、見過ごせない。。

 

状態管理は「riverpod」を使っており、初め、この辺の自分の使い方が下手なためかと思ったが、試しにTextFieldしかないシンプルなコードを作っても、同じ状況だった。

 

以下に、試行錯誤した対応の流れをメモ。

 

対応①:「requestFocus」する→解決せず

ネット上でもかなり調べたが、大方の情報は、TextFieldの「focus」属性に、FocusNodeのインスタンス(例えば「focusNode」)を設置し、

 

  • focusNode.requestFocus() もしくは、
  • FocusScope.of(context).requestFocus(focusNode)

 

のメソッドを実行すればよい、というもの。

 

しかし、これをやっても変化はなかった。

 

対応②:「SystemChannels」を使う → 解決せず

こちらの情報に、「SystemChannels」を使った方法として、

 

SystemChannels.textInput.invokeMethod(‘TextInput.show’);

 

というメソッドも紹介されていたため、試してみるも、やはり状況変わらず。

 

対応③:起動時に、いったんフォーカスを外し、再度フォーカス → 解決せず

こちらもよくネットで紹介されている

 

  • FocusManager.instance.primaryFocus?.unfocus() もしくは、
  • FocusScope.of(context).unfocus()

 

のメソッドを使い、アプリ起動時に、いったんフォーカスを外し、再度フォーカスするようにしてみたが、これも状況変わらず。

 

対応④:Timerクラスで待ってみる → 解決せず

こちらのイシュー情報で、

 

フォーカス外し

→ Timerクラスを用いて1ミリ秒待つ

→ フォーカス当てる

 

という方法でうまく行った、という情報もあり、それも試してみるが、依然として駄目。。

 

対応⑤:起動時に、別Widgetにフォーカスを移してから戻す → 解決せず

こちらのイシュー情報で、いったん別のWidgetにフォーカスを当て、目的のWidgetにフォーカスを戻すと機能した、とあったので、やってみるが、これも変わらず。

 

対応⑥:待ち時間を入れながら、いったんフォーカスを移し、戻す → 解決!

対応④と⑤を組み合わせ

 

Future.Delayedで200ミリ秒待つ

→ 別のFocusNodeにフォーカスを移す

→ Future.Delayedで200ミリ秒待つ

→ 元のFocusNodeにフォーカスを戻す

 

とやってみたところ、ようやく機能した(アプリ起動と同時に、キーボードを出現させられた)。

 

具体的なコードは以下。

 

initState内で、Widgetのビルドが終わってから実行する必要があるので、「WidgetsBinding.instance?.addPostFrameCallback」を使っている。

 

// 目的のWidget(TextFieldなど)に設置するFocusNode
final _focusNodeO = FocusNode();
// ダミーのFocusNode。特にWidgetには配置しない
final _focusNodeDummyO = FocusNode();

@override
  void initState() {

    WidgetsBinding.instance?.addPostFrameCallback((cb) async{

        // Widget全体のビルドが終わったら、200ミリ秒待った後に、
        // ダミーのFocusNode「_focusNodeDummyO」にフォーカスを移す
        await Future.delayed(Duration(milliseconds: 200));
        FocusScope.of(context).requestFocus(_focusNodeDummyO);

        // 再度200ミリ秒待った後に、本来のFocusNode「_focusNodeO」にフォーカスを戻す
        await Future.delayed(Duration(milliseconds: 200));
        FocusScope.of(context).requestFocus(_focusNodeO);

      },
    );

    super.initState();
  }

 

ダミーのFocusNodeは、特にこれ自体を設置するWidgetを用意しなくてもエラーにならなかったので、FocusNodeのインスタンスのみ、用意すれば良い

 

待つ時間は、100ミリ秒前後だと機能しなかった(機能したプロジェクトもあった、、、。この辺はコードの構造にも拠るのだろうか、、、)。

 

恐らく、release modeだと、処理速度が速いため、フォーカスオン→キーボード出現の処理が、順番どおり機能しないのかも?と推察(全然違っているかも知れませんが、、)。

 

なお、上記①〜⑤を試す過程で、releaseビルド初回は、アプリ起動と同時にキーボードが出るが、アプリを閉じて、再度起動させるとやっぱり出ない、という事が多かったので、初回ビルド時に機能しても安心できなかった。。

 

回りくどい方法で解決することになったが、引き続き調査して、もっとスマートな方法が見つかれば改善したい。

 

\ Flutterの学習で役立ったコンテンツ・書籍 /

 

 

 

 


Dart入門 – Dartの要点をつかむためのクイックツアー
タイトルとURLをコピーしました