Flutter, how to programatically change index of BottomNavigationBar from another file?
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",
),
),
),
);
}
}
aoiTenshi
Updated on January 04, 2023Comments
-
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 almost 2 yearsThat was very informative, thank you but that did not work for me :( I will look it up further.