[読書会]適応型デザイン設計における、切替ウィジェット間の共通情報の再利用化

Flutter で、アダプティブな(適応型デザインが要求されるウィジェットには、

ダイアログ(Dialogs)
・ナビゲーション(Navigation)
・カスタムレイアウト(Custom layout)

があります。(このことは、docs.flutter.dev/ui/adaptive-responsive で述べられています)

以下は、その際のアプローチ(抽象化、測定、分岐)のうちの、抽象化についての話題です。

例えば、画面が縦長もしくは小さいスマフォ画面時は、NavigationBar に、
画面が横長(ワイド画面)画面時は、NavigationRail に、切り替えて実装したい、という場合でも、
表示する内容には共通情報(アイコン、ラベル)があるはずです。

これらを、別のデータモデルクラスとして、分離する、というのが、上記の抽象化(つまり再利用化)になります。
(もちろん、最初から既に、これらをデータモデルクラス化してある場合は、この作業は完了していることになります)

以下は実装例です。

(例)共通情報の再利用化(データクラス化):
import 'package:flutter/material.dart';

//Destination データクラスの定義
class Destination {
  final String label;
  final IconData icon;

  const Destination({required this.label, required this.icon});
}

//実際に NavigationBar や NavigationRail に使用する Destination のリスト
const List<Destination> destinations = <Destination>[
  Destination(label: 'Home', icon: Icons.home),
  Destination(label: 'Profile', icon: Icons.person),
  Destination(label: 'Settings', icon: Icons.settings),
];

//メインウィジェット
class AdaptiveNavigationExample extends StatelessWidget {
  const AdaptiveNavigationExample({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //MediaQuery を使って画面の横幅を取得
    final bool useNavigationRail 
     = MediaQuery.of(context).size.width >= 600;

    return Scaffold(
      body: Row(
        children: [
          if (useNavigationRail)
            NavigationRail(
              destinations: destinations
                  .map((destination) => NavigationRailDestination(
                        icon: Icon(destination.icon),
                        label: Text(destination.label),
                      ))
                  .toList(),
              selectedIndex: 0, //選択されたアイテムのインデックス(例として0)
              onDestinationSelected: (int index) {
                //選択されたときの処理
              },
            )
          else
            BottomNavigationBar(
              items: destinations
                  .map((destination) => BottomNavigationBarItem(
                        icon: Icon(destination.icon),
                        label: destination.label,
                      ))
                  .toList(),
              currentIndex: 0, //選択されたアイテムのインデックス(例として0)
              onTap: (int index) {
                //選択されたときの処理
              },
            ),
          Expanded(
            child: Center(
              child: Text('Selected page content'),
            ),
          ),
        ],
      ),
    );
  }
}

void main() {
  runApp(MaterialApp(home: AdaptiveNavigationExample()));
}

上記により、以降、どのウィジェットに切り替えても、抽象化したデータの再利用が可能になります。

コメントを残す