Boost」など、さまざまなカンファレンスを企画・運営しています。BOOKS(コードジン・ブックス)は、CodeZineの連載からカットアップした、開発現場の課題解決に役立つ書籍シリーズです。便利な機能を実装するためのLocalKeyの使い方ここまで紹介したLocalKeyと異なる役割のキーがPageStorageKeyです。このキーはValueKeyを継承したクラスでもあるので、もちろん、これまでと同じ役割も担うこともできますが、親ウィジェットが持つ特別な機能の提供を受ける子ウィジェットとしての識別キーとして利用している一例です。PageStorageKeyの使い方PageStorageKeyは画面のスクロール位置などを保存しておく場合に利用することができます。図4のようにListViewを使った時に画面スクロールした状態から、他の画面に遷移し、再度、同じ画面に戻ったときには同じスクロール位置を再現してほしい場合があります。図4:page_storage_key_app.pngこのような機能を実装する場合には、画面をStackとして画面状態を維持したまま、次の画面を既存の画面の上部に表示するレイヤーとして実装する方法もあります。そのような画面のすべての状態を維持しなくても単にスクロール位置だけ戻してくれれば問題ないケースもあるはずです。そのような画面の指定した情報のみを維持するために利用するのがPageStorageKeyです。それらを実現しているのは図5のように複数のクラスで構成されていて、PageStorageKey自体は機能を利用するためのフラグ的機能とデータを識別するためのキーの役割のみになります。図5:PageStorageKeyと関連クラスの関係図そして、リスト6がListViewのスクロール位置を保存できるようにした実装例です。}}今回はサンプルの説明上わかりやすくするために(1)のようにスコープの最上位にインスタンスを作成しています。実際にはこのPageStorageBucketのライフサイクルがデータ保持のライフサイクルになります。実際はデータを保持してほしいスコープでインスタンスを作成するようにしてください。次に、(2)データを保持するためのPageStorageウィジェットを作成します。これは、PageStorageBucketが管理されているスコープをBuildContextを通じて見つけるために便宜上必要なウィジェットになります。(3)では、ListViewでスクロール位置を保存するための保存キーとしてPageStorageKeyを指定しています。このようにPageStorageを使わない場合のListViewとの違いが少なく、また、機能の関係性もわかりにくいためこのコードだけを見ても、よく役割がわかりにくいところがあると思います。その原因としては、ListViewのようなスクロール可能なウィジェットでは、あらかじめPageStorageKeyとPageStorageがあれば自動的にスクロール位置の保持が可能になるように実装されているためです。ListViewの他にも、GridViewなども同じことが可能でありそれらはScrollableのリファレンスを見るとPageStorageを利用することでスクロールの位置が保持できるクラスについての詳細を知ることができます。前回と今回の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での自由な描写方法や筆者が使っている便利なライブラリなどについて紹介したいと思います。NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Technologies。執筆コミュニティ「WINGSプロジェクト」代表。プラットフォームチームの意義と実践のポイント1DMM.comの施策から見る、事業をむしばむ「技術負債」への処方箋──リファクタリングの「言語化」でインシデントを予防2企業の7割超が「2025年の崖」を理解していないことが明らかに。プラットフォームチームの意義と実践のポイント1DMM.comの施策から見る、事業をむしばむ「技術負債」への処方箋──リファクタリングの「言語化」でインシデントを予防2企業の7割超が「2025年の崖」を理解していないことが明らかに。プラットフォームチームの意義と実践のポイント1DMM.comの施策から見る、事業をむしばむ「技術負債」への処方箋──リファクタリングの「言語化」でインシデントを予防2企業の7割超が「2025年の崖」を理解していないことが明らかに。NEW新着記事一覧を見るイベント今後の予定を見るCodeZineは、株式会社翔泳社が運営するソフトウェア開発者向けのWebメディアです。「デベロッパーの成長と課題解決に貢献するメディア」をコンセプトに、現場で役立つ最新情報を日々お届けします。イラストの無断転載を禁じます。記載されているロゴ、システム名、製品名は各社及び商標権者の登録商標あるいは商標です。