Keyについて
BuildContextと同様になんとなく使われている場合が多いのがKeyです。KeyもBuildContextの役割や制限と大きく関係しています。
Keyの役割
KeyはWidgetクラスのkeyパラメータとして利用され、大きく分けて表1のように2つの種類と使い方があります。
クラス名(種類) | 説明 |
---|---|
GlobalKey | Widgetツリーの親子関係などに依存せず、必要なStateを探すために利用される。 |
LocalKey | 画面上に表示する位置やリスト上に存在するデータセットの中でユニークさを保証するために利用される。 |
GlobalKeyを使う場合の多くが、Formのようにリファレンスなどで使い方も含めて説明されているので、その手順にそって記述しているだけでその意味を意識していないという方もいると思います。
しかし、これまでのWidgetツリーおよびBuildContextの関係を理解すれば、それらの利用方法の意味もより深くわかるはずです。
一方、LocalKeyはWidgetを画面表示する際の表示位置に関する制御や更新タイミングなど表示に関しての制御を行うために用いられます。この仕組みは表示上の最適化やパフォーマンスの都合もあり、少々複雑になるため説明は次回行います。
GlobalKeyの役割
ここまでの方法では、Widgetツリー(実体はそのWidgetを制御するBuildContextのツリー)の制限により、図10のようにツリー上の親や先祖上にないStateオブジェクトにはアクセスできません。
![図10:Widgetツリーの構造とその制限図](http://cz-cdn.shoeisha.jp/static/images/article/18583/18583_10.png)
しかし、実際のコード上ではこのような複雑な探索をする必要はなく、図11のように直接アクセスしたくなるのが通常です。
![図11:Keyを用いてWidgetツリーの制限を超えて必要なオブジェクトにアクセスする](http://cz-cdn.shoeisha.jp/static/images/article/18583/18583_11.png)
そのような場合に用いるのがGlobalKeyです。GlobalKeyを用いることでアプリケーションの任意の場所から、必要なStateオブジェクトにアクセスできるようになります。
GlobalKeyの利用例
リスト7は、第21回で使用したサンプルコードのGlobalKeyに関連する個所を中心に抜き出したものです。
// : (省略) class _LoginPage extends State<LoginPage>{ final _formState = GlobalKey<FormState>(); // (1) // : (省略) @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ Form( key: _formState, // (2) // 省略 ), // 省略 ], ) ); } // : (省略) Widget createLoginForm(BuildContext context){ return Column( // : (省略) children: [ // : (省略) ElevatedButton( onPressed: () async { final ok = _formState.currentState!.validate(); // (3) if(ok){ // : (省略) } }, child: Text('ログイン')) ], ); } // : (省略) }
(1)にてGlobalKeyを作成し、Widgetツリーの制限に関係せず、この変数にアクセスできるようにします。
(2)ではFormウィジェットが作成するFormStateをKeyからもアクセス可能にします。
そして、(3)でFormStateのインスタンスを取得し、そのメソッドを実行しています。
このように、GlobalKeyはBuildContextの仕組みや制限とともに考えると分かりやすいはずです。
最後に
今回は、BuildContext及びFlutter内部で構築されるWidgetツリーの特徴や制限などを中心に説明してきました。
Flutterだけではなく最近のプログラミングでは何らかのフレームワークを用いてアプリケーションを作成するケースが通常です。そのため、各機能について理解しているだけではなんとなくコードを書いているだけになり、問題が生じたときに解決方法がよく分からない場合があります。
また、このような理解は同じようなコードを何度も記述して経験により理解を深めていくということをしている方も多いと思います。しかし、フレームワークの理解は今回のように概念として理解することでその理解する速度は格段に上がります。
筆者も長い間、Contextという言葉のイメージができませんでした。そして、利用上、困るということは少なくあまり、深く考えることはありませんでした。
しかし、一度理解できると抽象的にイメージができるようになり、Flutterだけに限らず、他のフレームワークについても素早く理解ができるようになるはずです。
次回は、今回説明できなかったLocalKeyについて説明します。