how to use inner navigation if we using bottomNavigationBar on GetX

Viewed 1013

I'm trying to make navigation inside the body of the widget where the bottomNavigationBar remains outside, here is my code:

class WrapperController extends GetxController {
  int currentIndex = 0;
  List<BottomNavigationElement> items = [];

  Widget navigationTab({GlobalKey<NavigatorState> naviKey, Widget widget}) {
    return Navigator(
      key: naviKey,
      onGenerateRoute: (routeSettings) {
        return GetPageRoute(page: () => widget);
      },
    );
  }

  Widget bottomNavigationBar() {
    return BottomNavigationBar(
      selectedItemColor: Get.theme.accentColor,
      type: BottomNavigationBarType.fixed,
      currentIndex: currentIndex,
      backgroundColor: Get.theme.primaryColor,
      onTap: (int index) => _selectTab(index),
      items: items.map((e) => e.bottomBarItem).toList(),
    );
  }

  void _selectTab(int index) {
    if (index == currentIndex) {
      items[index]
          .navigationKey
          .currentState
          .popUntil((route) => route.isFirst);
    } else {
      currentIndex = index;
    }
    update();
  }

  Future<bool> onWillPop() async {
    final isFirstRouteInCurrentTab =
        !await items[currentIndex].navigationKey.currentState.maybePop();
    if (isFirstRouteInCurrentTab) {
      if (currentIndex != 0) {
        // _selectTab(1);
        return false;
      }
    }
    return isFirstRouteInCurrentTab;
  }

  @override
  void onInit() {
    super.onInit();
    items = [
      //Каталог
      BottomNavigationElement(
        bottomBarItem: BottomNavigationBarItem(
          icon: Icon(Icons.search),
          label: "Home",
        ),
        bottomBarView: HomePage(),
        navigationKey: Get.nestedKey('0'),
      ),
      //Любимое
      BottomNavigationElement(
        bottomBarItem: BottomNavigationBarItem(
          icon: Icon(Icons.favorite_border),
          label: "Favorites",
        ),
        bottomBarView: FavoritesPage(),
        navigationKey: Get.nestedKey('1'),
      ),
      //Корзина
      BottomNavigationElement(
        bottomBarItem: BottomNavigationBarItem(
          icon: Icon(Icons.shopping_cart_outlined),
          label: "Cart",
        ),
        bottomBarView: CartPage(),
        navigationKey: Get.nestedKey('2'),
      ),
      //Заказы
      BottomNavigationElement(
        bottomBarItem: BottomNavigationBarItem(
          icon: Icon(Icons.history),
          label: "History",
        ),
        bottomBarView: HistoryPage(),
        navigationKey: Get.nestedKey('3'),
      ),
      //Меню
      BottomNavigationElement(
        bottomBarItem: BottomNavigationBarItem(
          icon: Icon(Icons.menu),
          label: "Menu",
        ),
        bottomBarView: MenuPage(),
        navigationKey: Get.nestedKey('4'),
      ),
    ];
  }
}

class BottomNavigationElement {
  Widget bottomBarView;
  BottomNavigationBarItem bottomBarItem;
  GlobalKey<NavigatorState> navigationKey;
  BottomNavigationElement({
    @required this.bottomBarView,
    @required this.bottomBarItem,
    @required GlobalKey<NavigatorState> navigationKey,
  });
}

and here is the Wrapper widget :

class Wrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetBuilder<WrapperController>(builder: (controller) {
      return Scaffold(
        body: IndexedStack(
          index: controller.currentIndex,
          children: controller.items
              .map((e) => controller.navigationTab(
                    naviKey: e.navigationKey,
                    widget: e.bottomBarView,
                  ))
              .toList(),
        ),
        bottomNavigationBar: controller.bottomNavigationBar(),
      );
    });
  }
}

here is the HomePage("Search") which has a navigation button:

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Home"),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Navigator.of(context).push(
            MaterialPageRoute(
              builder: (context) => Detail(),
            ),
          ),
          child: Text("Detail"),
        ),
      ),
    );
  }
}

the question is, when I use Navigator.of (context) Get.to () instead, then the navigation is done entirely and not inside the body. I need internal navigation using Get.to (), how do I do this?

1 Answers

There is one quick solution

  1. Create a separate navigator for the bottom navbar (if you want to separate auth from the main logic).

  2. Code for that is:

    Expanded(
                child: Navigator(
                key: Get.nestedKey(1),
                initialRoute: controller.pageName.value,
                onGenerateRoute: HomeRouter.generateRoute,
              )
    )
    
  3. For Navigation

    void gotoPage(String page, BuildContext context) {
        pageName.value = page;
        print("Request to go to ${pageName.value}");
        Get.keys[1]!.currentState!.pushNamed(page);
        //if you want to change the URL in browser as well
        html.window.history.pushState(null, "/", page);
      }
    
Related