BilalShahid13 / PersistentBottomNavBar

A highly customizable persistent bottom navigation bar for Flutter
BSD 3-Clause "New" or "Revised" License
527 stars 395 forks source link

Update active bar item while navigation #307

Open bahadirarslan opened 2 years ago

bahadirarslan commented 2 years ago

Hello,

I am using Persistent Bottom Nav Bar in my project and I couldn't achieve a simple thing. While navigating from one screen to another without using the bottom nav bar; I want to update the selected (active) nav bar item according to navigated page.

But I can not make it.

final Map<String, Widget Function(BuildContext)> appRouter = {
    HomeScreen.routeName: (context) => const HomeScreen(),
    StatisticsScreen.routeName: (context) => const StatisticsScreen(),
    SettingsScreen.routeName: (context) => const SettingsScreen(),
  };

List<PersistentBottomNavBarItem> _navBarsItems() {
    return [
      PersistentBottomNavBarItem(
        icon: const Icon(CupertinoIcons.home),
        title: (L.of(context).home),
        activeColorPrimary: context.colors.tertiary,
        inactiveColorPrimary: context.colors.onSurfaceVariant,
        routeAndNavigatorSettings: RouteAndNavigatorSettings(
          initialRoute: '/',
          routes: appRouter,
        ),
      ),
      PersistentBottomNavBarItem(
          icon: const Icon(CupertinoIcons.chart_bar_alt_fill),
          title: (L.of(context).statistics),
          activeColorPrimary: context.colors.tertiary,
          inactiveColorPrimary: context.colors.onSurfaceVariant,
          routeAndNavigatorSettings: RouteAndNavigatorSettings(
            initialRoute: '/',
            routes: appRouter,
          )),

      PersistentBottomNavBarItem(
          icon: const Icon(CupertinoIcons.settings),
          title: (L.of(context).settings),
          activeColorPrimary: context.colors.tertiary,
          inactiveColorPrimary: context.colors.onSurfaceVariant,
          routeAndNavigatorSettings: RouteAndNavigatorSettings(
            initialRoute: '/',
            routes: appRouter,
          )),
    ];
  }

@override
  Widget build(BuildContext context) {
    // Size size = MediaQuery.of(context).size;
    return PersistentTabView(
      context,
      controller: _controller,
      screens: widget._pages,
      items: _navBarsItems(),

      confineInSafeArea: true,
      backgroundColor: context.colors.surface, // Default is Colors.white.
      handleAndroidBackButtonPress: true, // Default is true.
      resizeToAvoidBottomInset: true, // This needs to be true if you want to move up the screen when keyboard appears. Default is true.
      stateManagement: true, // Default is true.
      hideNavigationBarWhenKeyboardShows: true, // Recommended to set 'resizeToAvoidBottomInset' as true while using this argument. Default is true.
      decoration: NavBarDecoration(borderRadius: BorderRadius.circular(10.0), colorBehindNavBar: context.colors.surface),
      popAllScreensOnTapOfSelectedTab: true,
      popActionScreens: PopActionScreensType.all,
      itemAnimationProperties: const ItemAnimationProperties(
        // Navigation Bar's items animation properties.
        duration: Duration(milliseconds: 200),
        curve: Curves.ease,
      ),
      screenTransitionAnimation: const ScreenTransitionAnimation(
        // Screen transition animation on change of selected tab.
        animateTabTransition: true,
        curve: Curves.ease,
        duration: Duration(milliseconds: 200),
      ),
      navBarStyle: NavBarStyle.style14, // Choose the nav bar style with this property.
    );
  }

In this example, I try to navigate from HomeScreen to SettingsScreen and I tried all the ways I know. But in the end, I can navigate successfully but the active navigation bar item is at the bottom nav bar still HomeScreen.

PersistentNavBarNavigator.pushNewScreenWithRouteSettings(
                          context,
                          settings: RouteSettings(name: SettingsScreen.routeName),
                          screen: SettingsScreen(),
                          withNavBar: true,
                          pageTransitionAnimation: PageTransitionAnimation.cupertino,
                        );

or

Navigator.of(context).pushNamed(SettingsScreen.routeName);

or

return PersistentNavBarNavigator.pushNewScreen(
      this,
      screen: SettingsScreen(),
      withNavBar: true, // OPTIONAL VALUE. True by default.
      pageTransitionAnimation: PageTransitionAnimation.cupertino,
    );

What is the correct way of doing this?

quen09t commented 1 year ago

Did you find a solution for this ?

PINHOf commented 1 year ago

Well, I was looking for a solution that I thought it was already integrated in the plugin, but since I couldn't find any, I manage to get this working just by having a callback.

So, lets say you have the following screens:

  1. Dashboard screen
  2. Posts screen
  3. Account screen

If in the Dashboard screen you wish to have a button to navigate to Account screen and keep the Navigation bar aligned, here's how you do it:

home_screen.dart

// Defines the initial index of screens
PersistentTabController tabController = PersistentTabController(initialIndex: 0);

// Create your persistentTabView normally
@override
Widget build(BuildContext context) {
    return PersistentTabView(
        controller: tabController,
        screens: screens(),
        ... etc
    );
}

List<Widget> screens() {
    return [
      DashboardScreen()
        onScreenChanged: (int screenIndex) {
            tabController.jumpToTab(screenIndex);
        },
      ),
      PostsScreen(),
      AccountScreen(),
    ];
}

dashboard_screen.dart

class DashboardScreen extends StatefulWidget {
  final void Function(int) onScreenChanged;

  const DashboardScreen({
    required this.onScreenChanged,
    Key? key,
  }) : super(key: key);

  @override
  _DashboardScreenState createState() => _DashboardScreenState();
}

class _DashboardScreenState extends State<DashboardScreen> 
{
    @override
    Widget build(BuildContext context) {
        return TextButton(
          child: const Text('Go to account screen'),
          onPressed: () => widget.onScreenChanged(2),
        );
    }
}