Flutter-BottomNavigationBarとNavigationBar

BottomNavigationBarとNavigationBarは、基本的にScaffoldのBottomに配置するナビゲーションバーという部品になる。

BottomNavigationBarはMaterial 2仕様でNavigationBarはMaterial 3仕様という違いがあるだけ。

BottomNavigationBar class - material library - Dart API
API docs for the BottomNavigationBar class from the material library, for the Dart programming language.

上記のSee also:の中に「NavigationBar, this widget’s replacement in Material Design 3.」と書かれているし、Material 3のNavigation barのOverviewにも「There’s one type of navigation bar in Material. In M2, this component is named bottom navigation.」と記載されている。

ただBottomNavigationBarとNavigationBarはFlutterでは異なるクラスになるので、ThemeDataでuseMaterial3をtrueにしただけで切り替わるということではない。

そこでBottomNavigationBarにインターフェースが似た形でM2/M3の状態に合わせてBottomNavigationBar、NavigationBarを切り替えるウィジェットを作ってみた。

ソースコード

クラスのコードは以下の様な感じ。
色関係については割愛している。

/// [ThemeData]の[useMaterial3]の設定により[BottomNavigationBar]か[NavigationBar]
/// を切り替えて使用し、[Scaffold]の[bottomNavigationBar]に設定するナビゲーションバーを
/// 表示する
class AltBottomNavBar extends StatelessWidget {
  const AltBottomNavBar(
      {super.key, required this.items, this.onTap, this.currentIndex = 0});

  /// Defines the appearance of the button items that are arrayed within the
  /// bottom navigation bar.
  final List<BottomNavigationBarItem> items;

  /// Determines which one of the [items] is currently selected.
  ///
  /// When this is updated, the destination (from [items]) at
  /// [currentIndex] goes from unselected to selected.
  final int currentIndex;

  /// Called when one of the [items] is tapped.
  final ValueChanged<int>? onTap;

  @override
  Widget build(BuildContext context) {
    final useMaterial3 = Theme.of(context).useMaterial3;

    return !useMaterial3
        ? BottomNavigationBar(
            useLegacyColorScheme: false,
            items: items,
            currentIndex: currentIndex,
            onTap: onTap,
          )
        : NavigationBar(
            destinations: items
                // BottomNavigationBarItemからNavigationDestinationに変換
                .map<Widget>((e) => NavigationDestination(
                      label: e.label!,
                      selectedIcon: e.activeIcon,
                      icon: e.icon,
                      tooltip: tooltip: e.tooltip ?? "",
                    ))
                .toList(),
            selectedIndex: currentIndex,
            onDestinationSelected: onTap,
            labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
          );
  }
}

BottomNavigationBarItemからの変換

一番大きな変更点は、受け入れる表示アイテムがBottomNavigationBarItemからWidgetに変わった点。

NavigationBarはWidgetだけど実際に使用されるウィジェットはNavigationDestinationになるので、それへの変換を行う。

とは言っても、BottomNavigationBarItem自体はlabel, activeIcon, icon, tooltipを入れるコンテナとしての役割しか持っていないので、List.mapでNavigationDestinationに変換するだけで問題はない。

ツールチップの取り扱い

変換で注意が必要なのがツールチップ。
BottomNavigationBarではtooltipがnullの場合ツールチップの表示はされないのだけど、NavigationBarではtooltipがnullの場合labelと同じものが表示される。

上の動画は、前半がBottomNavigationBarで後半がNavigationBarになる。
BottomNavigationBarではツールチップが表示されいないけどNavigationBarでは表示されているのが見て取れると思う。

そういう意味で、NavigationDestinationのtooltipにはBottomNavigationBarItemのtooltipがnullの場合、空文字(“”)を設定するようにしている。

labelBehaviorの設定

BottomNavigationBarではデフォルトでは現在アクティブなもののもみlabelが表示されるが、NavigationBarはデフォルトすべての項目のlabelが表示される。

BottomNavigationBarの表示方法に合わせる場合「labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected」とすることで合わせることができる。

  • BottomNavigationBar
  • NavigationBar

コメント

タイトルとURLをコピーしました