Flutter, how to programatically change index of BottomNavigationBar from another file?

218

Please refer to below example code

ValueListenableBuilder widget. It is an amazing widget. It builds the widget every time the valueListenable value changes. Its values remain synced with there listeners i.e. whenever the values change the ValueListenable listen to it. It updates the UI without using setState() or any other state management technique.

In Dart, a ValueNotifier is a special type of class that extends a ChangeNotifer . ... It can be an int , a String , a bool or your own data type. Using a ValueNotifier improves the performance of Flutter app as it can help to reduce the number times a widget gets rebuilt.

ValueListenableBuilder will listen for changes to a value notifier and automatically rebuild its children when the value changes.

ValueNotifer & ValueListenableBuilder can be used to hold value and update widget by notifying its listeners and reducing number of times widget tree getting rebuilt.

For example refer to this link

void main() {
  runApp(MyApp());
}

final ValueNotifier selectedIndexGlobal = ValueNotifier(0); // Add this ValueNotifier which is globally accessible throughtout your project

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: NavbarRouter(),
      
    );
  }
}

class YesillemePage extends StatelessWidget {
  const YesillemePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.pink,
    );
  }
}

class YesillenecekPaletListesiPage extends StatelessWidget {
  const YesillenecekPaletListesiPage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.purple,
    );
  }
}

class PaletIcerigiPage extends StatelessWidget {
  const PaletIcerigiPage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.blue,
    );
  }
}

class NavbarRouter extends StatefulWidget {
  const NavbarRouter({Key key}) : super(key: key);

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

class _NavbarRouterState extends State<NavbarRouter> {
  final List<Widget> pages = [
    YesillemePage(),
    YesillenecekPaletListesiPage(),
    PaletIcerigiPage(),
    RedPage(),
  ];

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder(
      valueListenable: selectedIndexGlobal,
      builder: (context, val, child) {
        return Scaffold(
          body: IndexedStack(
            index: selectedIndexGlobal.value,
            children: pages,
          ),
          bottomNavigationBar: SizedBox(
            height: MediaQuery.of(context).size.height * .11,
            child: BottomNavigationBar(
              items: const <BottomNavigationBarItem>[
                BottomNavigationBarItem(
                    icon: Icon(Icons.bar_chart), label: "Yeşilleme\n  Kontrol"),
                BottomNavigationBarItem(
                    icon: Icon(Icons.featured_play_list_outlined),
                    label: "Yeşillenecek\n       Palet"),
                BottomNavigationBarItem(
                    icon: Icon(
                      Icons.search,
                      color: Colors.grey,
                    ),
                    label: "Palet İçeriği"),
                BottomNavigationBarItem(
                    icon: Icon(Icons.warning_amber_outlined), label: "Red")
              ],
              backgroundColor: Colors.orange[300],
              currentIndex: selectedIndexGlobal.value,
              type: BottomNavigationBarType.fixed,
              selectedItemColor: Colors.white,
              selectedFontSize: 12.0,
              unselectedFontSize: 10.0,
              onTap: (index) {
               
                if (index == 0) {
                  focusNodeY1!.requestFocus();
                } else if (index == 3) {
                  focusNodeRed!.requestFocus();
                } else if (index == 2) {
                  return;
                }
                selectedIndexGlobal.value = index;
                
              },
            ),
          ),
        );
      },
    );
  }
}

class RedPage extends StatefulWidget {
  const RedPage({Key key}) : super(key: key);

  @override
  State<RedPage> createState() => _RedPageState();
}

class _RedPageState extends State<RedPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: InkWell(
          onTap: () {
            selectedIndexGlobal.value = 0;
          },
          child: Text(
            "Change Index",
          ),
        ),
      ),
    );
  }
}

Share:
218
aoiTenshi
Author by

aoiTenshi

Updated on January 04, 2023

Comments

  • aoiTenshi
    aoiTenshi over 1 year

    I want to change my BottomNavigationBar's selected index from one of its items but that item is implemented in a different .dart file and is a separate StatefulWidget. My BottomNavigationBar (navbar.dart):

    class NavbarRouter extends StatefulWidget {
      const NavbarRouter({Key? key}) : super(key: key);
    
      @override
      _NavbarRouterState createState() => _NavbarRouterState();
    }
    
    class _NavbarRouterState extends State<NavbarRouter> {
      final List<Widget> pages = [
        const YesillemePage(),
        const YesillenecekPaletListesiPage(),
        const PaletIcerigiPage(),
        const RedPage()
      ];
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: IndexedStack(
              index: selectedIndexGlobal,
              children: pages,
            ),
            bottomNavigationBar: SizedBox(
              height: MediaQuery.of(context).size.height * .11,
              child: BottomNavigationBar(
                items: const <BottomNavigationBarItem>[
                  BottomNavigationBarItem(
                      icon: Icon(Icons.bar_chart), label: "Yeşilleme\n  Kontrol"),
                  BottomNavigationBarItem(
                      icon: Icon(Icons.featured_play_list_outlined),
                      label: "Yeşillenecek\n       Palet"),
                  BottomNavigationBarItem(
                      icon: Icon(
                        Icons.content_paste_search,
                        color: Colors.grey,
                      ),
                      label: "Palet İçeriği"),
                  BottomNavigationBarItem(
                      icon: Icon(Icons.warning_amber_outlined), label: "Red")
                ],
                backgroundColor: Colors.orange[300],
                currentIndex: selectedIndexGlobal,
                type: BottomNavigationBarType.fixed,
                selectedItemColor: Colors.white,
                selectedFontSize: 12.0,
                unselectedFontSize: 10.0,
                onTap: (index) {
                  setState(() {
                    if (index == 0) {
                      focusNodeY1!.requestFocus();
                    } else if (index == 3) {
                      focusNodeRed!.requestFocus();
                    } else if (index == 2) {
                      return;
                    }
                    selectedIndexGlobal = index;
                  });
                },
              ),
            ));
      }
    } 
    

    And the place I want it to change (greenitem.dart, 2nd item):

     DataRow(onLongPress: () {
                                   //here i wanto to go to index 2                 
                                                  },
                                                  color: item.ACIL == "X"
                                                      ? MaterialStateProperty.all<
                                                          Color>(Colors.red)
                                                      : MaterialStateProperty.all<
                                                          Color>(Colors.white),
                                                  cells: [
                                                    DataCell(Text(item.PLTNO!)),
                                                    DataCell(Text(
                                                        item.BOLUM!.toString())),
                                                  ]))
    

    What I tried:

    onLongPress: () {
          setState(){selectedIndexGlobal = 2;}                              
       },
    

    This does not refresh the state of the navbar so didn't work.

    And I tried to give a GlobalKey to my NavbarRouter and

    onLongPress: () {
        navbarKey.currentState!.setState(() {selectedIndexGlobal = 2});               
     },
    

    But that gave me a "duplicate global key detected in widget tree" error. What should I do?

  • aoiTenshi
    aoiTenshi almost 2 years
    That was very informative, thank you but that did not work for me :( I will look it up further.