🍎 FlutterでbottomNavigationBarを固定して画面遷移する

2021-01-10 #Development

ちょっと作りたいアプリができたので、Flutter を触っています。

以前お仕事で触った時には表題の件にとても苦労したのですが、今だと最適解に見える例がいくつがアップされていました。ありがたや…

ほぼほぼ似た感じのコードを使わせていただいたのですが、以下の改良を加えてみました。

  • タブ内だけでなくタブの外(一つ上の階層)にも画面を開けるように
  • 上記理由で GlobalKey を複数使うので、Singleton に纏めておいて必要な時にそこから適宜呼び出すように
  • Routing や TabItem の設定を別ファイルで作成し、なるべく他のアプリ作る時にも使いまわせるような構造に
  • ページ遷移の時に次の画面に引数を渡せるように

ポイントとしては root と tab で使用している GlobalKey をそれぞれ Singlton に格納しておいて、そこから呼び出すようにしたり、

class NavigationService {
  //singleton
  static final _instance = NavigationService._internal();
  NavigationService._internal();
  static NavigationService getInstance() {
    return _instance;
  }

  //root state
  GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>();

  //tab state
  TabItem currentTab = TabItem.home;
  Map<TabItem, GlobalKey<NavigatorState>> tabNavigatorKeys = {
    TabItem.home: GlobalKey<NavigatorState>(),
    TabItem.star: GlobalKey<NavigatorState>(),
    TabItem.settings: GlobalKey<NavigatorState>(),
  };

  static NavigatorState getRootState() {
    return NavigationService.getInstance().rootNavigatorKey.currentState;
  }

  static NavigatorState getCurrentTabState() {
    return NavigationService.getInstance()
        .tabNavigatorKeys[NavigationService.getInstance().currentTab]
        .currentState;
  }

  static Future<dynamic> pushInTab(String routeName, {Object arguments}) {
    return Navigator.push(
      NavigationService.getCurrentTabState().context,
      Routes.onGenerateRoute(
        RouteSettings().copyWith(name: routeName, arguments: arguments),
      ),
    );
  }

  ...
}

あとは引数として渡す値の中に fullscreenDialog を入れておいて、同じページでも onGenerateRoute の時にそれを参照して渡すようにしたり(これで同じページをタブ内でも外でも使えるようになります。実際使うかわからないですが…)

class ScreenArguments {
  final String message;
  final bool fullscreenDialog;

  ScreenArguments(this.message, {this.fullscreenDialog = false});
}
return MaterialPageRoute(
  builder: (context) => DammyPage(
    title: 'page name',
    arguments: settings.arguments,
  ),
  fullscreenDialog: settings.arguments.fullscreenDialog,
);

チーム仕事の時にはあんまりこんな書き方をしなさそうですが、個人プロジェクトなので自分個人の使いやすさ的なところに焦点を当てて試行錯誤しています。他にもちょこちょこ触っているのですが未来の自分用メモみたいなものなので、あとは GitHub のリンクを貼っておきます。

comments powered by Disqus
Profile
😛

石原 悠 / Yu Ishihara

デザインとプログラミングとヨーグルト作りが好きです。