SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Flutterで始めるモバイルアプリ開発

LocalKeyがわかるとFlutterの理解がより深まる

Flutterで始めるモバイルアプリ開発 第26回

  • X ポスト
  • このエントリーをはてなブックマークに追加

便利な機能を実装するためのLocalKeyの使い方

 ここまで紹介したLocalKeyと異なる役割のキーがPageStorageKeyです。

 このキーはValueKeyを継承したクラスでもあるので、もちろん、これまでと同じ役割も担うこともできますが、親ウィジェットが持つ特別な機能の提供を受ける子ウィジェットとしての識別キーとして利用している一例です。

PageStorageKeyの使い方

 PageStorageKeyは画面のスクロール位置などを保存しておく場合に利用することができます。例えば、図4のようにListViewを使った時に画面スクロールした状態から、他の画面に遷移し、再度、同じ画面に戻ったときには同じスクロール位置を再現してほしい場合があります。

図4:page_storage_key_app.png
図4:page_storage_key_app.png

 このような機能を実装する場合には、画面をStackとして画面状態を維持したまま、次の画面を既存の画面の上部に表示するレイヤーとして実装する方法もあります。しかし、そのような画面のすべての状態を維持しなくても単にスクロール位置だけ戻してくれれば問題ないケースもあるはずです。

 そのような画面の指定した情報のみを維持するために利用するのがPageStorageKeyです。ただし、それらを実現しているのは図5のように複数のクラスで構成されていて、PageStorageKey自体は機能を利用するためのフラグ的機能とデータを識別するためのキーの役割のみになります。

図5:PageStorageKeyと関連クラスの関係図
図5:PageStorageKeyと関連クラスの関係図

 そして、リスト6がListViewのスクロール位置を保存できるようにした実装例です。

[リスト6]スクロール位置を保持できるListViewの実装コード例(lib/child/PageStorageKeyPage.dartの一部抜粋)
// (1) 最上位のスコープにデータ保存用のインスタンスを作成
final bucket = PageStorageBucket();

class PageStorageKeyPage extends StatelessWidget {

  const PageStorageKeyPage({super.key});

  @override
  Widget build(BuildContext context) {
    // (2) PageStorageを使う
    return PageStorage(
      bucket: bucket,
      child: Scaffold(
        appBar: AppBar(title: const Text('PageStorageKey'), actions: const []),
        body: ListView.builder(
            // (3) 保存用のキーを指定
            key: const PageStorageKey<String>("list"),
            itemCount: 20,
            itemBuilder: (context, index) {
              return Container(
                // : (省略)
              );
            }),
      ),
    );
  }
}

 今回はサンプルの説明上わかりやすくするために(1)のようにスコープの最上位にインスタンスを作成しています。実際にはこのPageStorageBucketのライフサイクルがデータ保持のライフサイクルになります。

 実際はデータを保持してほしいスコープでインスタンスを作成するようにしてください。次に、(2)データを保持するためのPageStorageウィジェットを作成します。

 これは、PageStorageBucketが管理されているスコープをBuildContextを通じて見つけるために便宜上必要なウィジェットになります。そして、(3)では、ListViewでスクロール位置を保存するための保存キーとしてPageStorageKeyを指定しています。

 このようにPageStorageを使わない場合のListViewとの違いが少なく、また、機能の関係性もわかりにくいためこのコードだけを見ても、よく役割がわかりにくいところがあると思います。

 その原因としては、ListViewのようなスクロール可能なウィジェットでは、あらかじめPageStorageKeyとPageStorageがあれば自動的にスクロール位置の保持が可能になるように実装されているためです。

 ListViewの他にも、GridViewなども同じことが可能でありそれらはScrollableのリファレンスを見るとPageStorageを利用することでスクロールの位置が保持できるクラスについての詳細を知ることができます。

筆者が感じたBuildContextやKeyの役割と理解

 前回と今回のBuildContextとKeyの内容はわかりにくいと感じる部分もあったかと思います。どちらも機能としては難しいことをしていないにもかかわらず、その目的はわかりにくいと感じていました。そこで筆者が感じたもっと深い部分での役割について、主観的ではありますが、参考まで記したいと思います。

 筆者が最もFlutterに対して違和感を感じていた部分が、表示機能を持たないWidgetの存在でした。しかし、Contextの役割とKeyの役割を理解する際には、表示機能をもたないWidgetの機能に着目するとその目的がより強く浮かびあがってきたと感じます。

 筆者の経験上、UIアプリケーションで生じる難解な不具合の多くが非UI機能部分とUI部分の連携をする際にUI上の制約から生じる表示や更新ライフサイクルと同期がとれず問題が生じるケースがあります。

 特にこのような問題は再現することが難しいケースが多く、さらに利用者毎に生じる現象がちょっとだけ異なる特徴もでやすいです。つまり、まれにしか発生しないが、発生してもその原因や条件などがわかりにくいことです。

 しかし、ビジネスロジック上のツリー構造やライフサイクルとデザインや装飾などを含めたUI上のツリー構造やライフサイクルは多くの場合一致しません。そのため、多くのUIフレームワークではこの2つの構造をできるだけ疎結合を維持しながら管理できるようにします。

 一方、Flutterはこのような疎結合の解決方法ではなく、あえて密に結合させることで問題をはかろうとしていると感じます。つまり問題が起きにくいUIアプリケーションを作成するためには、UIのライフサイクル上で非UI処理も同様に記述できれば、この問題は生じにくくなります。

 ただし問題は生じにくくなりますが、非UIの処理が記述しにくくなります。そこでそのギャップを埋めるために利用できるのがBuildContextとKeyだと思いました。

最後に

 今回の記事内に説明にはありませんが、サンプルコードにはスクロール位置ではなく、フォームのテキストフィールドに入力した内容を保持するためのコード(MyFormPage.dart)を用意しました。実装も今回の内容をより理解しやすくするためにできるだけ自前で実装を行っています。より理解を深めたいと思う方は、それらのコードも合わせて参照していただけると幸いです。

 また、ここまでのFlutterの連載でほぼ全容については説明できたと思います。次回からは、Flutterでの自由な描写方法や筆者が使っている便利なライブラリなどについて紹介したいと思います。

参考資料

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Flutterで始めるモバイルアプリ開発連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/19106 2024/03/13 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング