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()));
}
上記により、以降、どのウィジェットに切り替えても、抽象化したデータの再利用が可能になります。