[Flutter]ofメソッドは、上位のInheritedWidgetを探している目印

 ofメソッドはInheritedWidgetにアクセスするための慣習的な方法であり、多くの場面でInheritedWidgetを検索する目印や手がかりとして使われます。

 以下のTheme、MediaQueryなどは、内部にInheritedWidgetに相当する機能を持っており、ofメソッドを利用してそのInheritedWidgetに格納されているデータにアクセスしています。

  1. Theme.of(context)
    現在のテーマデータを取得します。
  2. MediaQuery.of(context)
    メディアのクエリデータ(例:画面のサイズや向きなど)を取得します。
  3. Navigator.of(context)
    ナビゲーションのスタックを操作するためのNavigatorを取得します。
  4. Scaffold.of(context)
    現在のScaffoldウィジェットにアクセスします。

 これらのメソッドは、指定されたBuildContextを起点にウィジェットツリーを遡り、該当するInheritedWidgetやその他の親ウィジェットにアクセスします。このofメソッドを見ると、多くの場合で上位のウィジェットツリーから何らかの情報や機能を取得しようとしています。

Theme.of(context)の場合

 Theme.of(context)の場合、Theme自体がInheritedWidgetを直接継承しているわけではありませんが、内部でInheritedThemeというInheritedWidgetに相当する機能を使用して、テーマデータを子ウィジェットに渡します。

 Themeウィジェットは、アプリケーションのテーマデータを保持し、子ウィジェットにそのテーマデータを提供する役割を持っています。実際には、Themeウィジェットの内部でInheritedThemeという別のウィジェット(これがInheritedWidgetを継承しています)を使用して、テーマデータを子ウィジェットに渡す仕組みとなっています。

 Theme.of(context)を使用すると、このInheritedThemeをウィジェットツリーで探し、テーマデータを取得します。これにより、アプリケーション全体で一貫したデザインや外観を実現することができます。

 つまり、Theme.of(context)は、暗黙的にInheritedTheme(またはそれを継承する特定のInheritedWidget)を背後で使用してテーマデータを取得しています。

MediaQuery.of(context)の場合

 MediaQueryは、デバイスのメディアクエリ情報(画面サイズ、向き、明るさなど)を取得するためのウィジェットです。この情報は、レスポンシブなデザインを実装する際に非常に役立ちます。

 MediaQuery.of(context)を使用すると、現在のBuildContextに関連する最も近いMediaQueryデータを取得することができます。これは、BuildContextを起点として、ウィジェットツリーを遡りながら、最も近いMediaQueryウィジェットを探し、そのMediaQueryウィジェットが保持しているメディアクエリ情報を返します。

 多くの場合、MaterialAppWidgetsAppウィジェットの中にMediaQueryウィジェットが自動的に組み込まれているため、ウィジェットツリーのどこからでもMediaQuery.of(context)を使用してメディアクエリ情報にアクセスすることができます。

Navigator.of(context)の場合

 Navigator.of(context)も同様の仕組みで動作します。具体的には、Navigatorはアプリケーションのルートナビゲーションスタックを管理するためのウィジェットであり、それ自体がInheritedWidgetを直接継承しているわけではありません。しかし、内部的にNavigatorInheritedWidgetのメカニズムを利用して、子ウィジェットツリーにナビゲーションスタックへのアクセスを提供します。

 Navigator.of(context)を呼び出すと、現在のBuildContextを起点にウィジェットツリーを遡りながら最も近いNavigatorウィジェットを探します。そして、そのNavigatorウィジェットが保持しているナビゲーションスタックにアクセスすることができます。

 Flutterアプリのほとんどでは、MaterialAppCupertinoAppの中にNavigatorウィジェットが組み込まれており、これによって画面遷移や戻る動作などのナビゲーション操作が可能になります。Navigator.of(context)を使用してこのナビゲーション機能にアクセスすることが一般的です。

Scaffold.of(context)の場合

 ScaffoldはMaterial Designの基本的なビジュアルレイアウト構造を提供するウィジェットです。これにはアプリケーションバー、ドロワー、フローティングアクションボタン、ボトムシート、スナックバーなどの多くの基本的なUIコンポーネントが含まれます。

 Scaffold.of(context)は、指定されたBuildContextに最も近いScaffoldウィジェットを探して返します。これにより、子ウィジェットからScaffoldの機能、例えばスナックバーの表示など、を利用することができます。

 実際の使い方としては、たとえばあるFlatButtononPressedコールバック内でスナックバーを表示する場面などで使われます。このように、あるイベントが発生したときに、親のScaffoldに対して何らかの操作を行いたい場合に、Scaffold.of(context)を利用してアクセスすることが一般的です。

DefaultTextStyle.ofの場合

 DefaultTextStyleInheritedWidgetを利用しています。

 DefaultTextStyleは、Textウィジェットにデフォルトのスタイル(文字の色、フォント、サイズなど)を提供するウィジェットです。このウィジェットをツリーの任意の位置に配置することで、その下の子ウィジェットにデフォルトのテキストスタイルを提供することができます。

 内部的に、DefaultTextStyleInheritedWidgetの仕組みを利用しています。これにより、子ウィジェットツリーのどこからでもそのデフォルトスタイルに効率的にアクセスすることができます。

 具体的には、以下のようにしてDefaultTextStyleの現在のスタイルを取得することができます。

Dart
TextStyle? style = DefaultTextStyle.of(context).style;

 このように、DefaultTextStyleを使うことで、複数のTextウィジェットに一貫したスタイルを適用することが簡単になります。