So I have a Row and two containers; first for selection of page and second for navigating to that selected page. I pass a string value to the 2nd container for identification which page should I navigate towards.
use NavigationRail
example:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
NavigationRail(
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: NavigationRailLabelType.selected,
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.favorite_border),
selectedIcon: Icon(Icons.favorite),
label: Text('First'),
),
NavigationRailDestination(
icon: Icon(Icons.bookmark_border),
selectedIcon: Icon(Icons.book),
label: Text('Second'),
),
NavigationRailDestination(
icon: Icon(Icons.star_border),
selectedIcon: Icon(Icons.star),
label: Text('Third'),
),
],
),
const VerticalDivider(thickness: 1, width: 1),
// This is the main content.
Expanded(
child: Center(
child: Text('selectedIndex: $_selectedIndex'),
),
)
],
),
);
}
}
here is the simple solution, you can add page or widget to list then add setstate and index of widget to button onPressed function. when you pressed to button its gonna show the page
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedIndex = 0;
final screen = [
const Center(child: Text('Home')),
const Center(child: Text('Search')),
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
Container(
width: 200,
color: Colors.red,
child: Column(
children: [
IconButton(
onPressed: () {
setState(() {
_selectedIndex = 0;
});
},
icon: Icon(Icons.home)),
IconButton(
onPressed: () {
setState(() {
_selectedIndex = 1;
});
},
icon: Icon(Icons.search)),
],
),
),
screen[_selectedIndex]
],
),
);
}
}
Related
I would like to set a new BottomNavigationBar after i've clicked on one of my ListTile. Right now, i am getting two BottomNavigationbar after I've clicked on one of them.
Below is my code where I setup the first bar:
class CoachNav extends StatefulWidget {
const CoachNav({Key? key}) : super(key: key);
#override
State<CoachNav> createState() => _CoachNavState();
}
class _CoachNavState extends State<CoachNav> {
int _selectedIndex = 0;
final List<Widget> _widgetOptions = <Widget>[
const TeamListView(),
const SettingsFormView(),
];
Widget? _onItemTap(int index) {
setState(() {
_selectedIndex = index;
});
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.groups),
label: "Mes équipes",
),
BottomNavigationBarItem(
icon: Icon(Icons.settings), label: "Paramètres"),
],
currentIndex: _selectedIndex,
onTap: _onItemTap,
),
);
}
}
Then, there is the code where I setup the second bar:
class TeamNav extends StatefulWidget {
const TeamNav({Key? key}) : super(key: key);
#override
State<TeamNav> createState() => _TeamNavState();
}
class _TeamNavState extends State<TeamNav> {
int _selectedIndex = 0;
final List<Widget> _widgetOptions = <Widget>[
const PlayersListView(),
const GamesListView(),
];
Widget? _onItemTap(int index) {
setState(() {
_selectedIndex = index;
});
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.group),
label: "Mes joueurs",
),
BottomNavigationBarItem(
icon: Icon(Icons.sports_basketball), label: "Mes matchs"),
],
currentIndex: _selectedIndex,
onTap: _onItemTap,
),
);
}
}
Here are two screenshots of what is happening
First Bar
Second Bar
---------------- EDIT ----------------------
This is what I get when I make the _widgetOptions texts
I got the first bar... whith the content from where the second bar should Appear
this is the snippet of the code I got as answer below:
lass App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(home: CoachNav());
}
}
class TeamNav extends StatefulWidget {
const TeamNav({Key? key}) : super(key: key);
#override
State<TeamNav> createState() => _TeamNavState();
}
class _TeamNavState extends State<TeamNav> {
int _selectedIndex = 0;
final List<Widget> _widgetOptions = <Widget>[
Text("PlayersListView"),
Text("PlayersListView"),
];
Widget? _onItemTap(int index) {
setState(() {
_selectedIndex = index;
});
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
/* floatingActionButton: FloatingActionButton(onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => CoachNav(),
));
}),*/
body: Container(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.group),
label: "Mes joueurs",
),
BottomNavigationBarItem(
icon: Icon(Icons.sports_basketball), label: "Mes matchs"),
],
currentIndex: _selectedIndex,
onTap: _onItemTap,
),
);
}
}
class CoachNav extends StatefulWidget {
const CoachNav({Key? key}) : super(key: key);
#override
State<CoachNav> createState() => _CoachNavState();
}
class _CoachNavState extends State<CoachNav> {
int _selectedIndex = 0;
final List<Widget> _widgetOptions = <Widget>[
Text("PlayersListView"),
Text("PlayersListView"),
];
Widget? _onItemTap(int index) {
setState(() {
_selectedIndex = index;
});
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: _widgetOptions.elementAt(_selectedIndex),
),
//floatingActionButton: FloatingActionButton(onPressed: () {}),
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.groups),
label: "Mes équipes",
),
BottomNavigationBarItem(
icon: Icon(Icons.settings), label: "Paramètres"),
],
currentIndex: _selectedIndex,
onTap: _onItemTap,
),
);
}
}
This is the code that have the text shown in the third screenshot.
class PlayersListView extends StatelessWidget {
const PlayersListView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(body: Text("Playerslist"),);
}
}
I think you have a design problem.
In your case, the best way is this one, i think.
When you tap on a tile you should fix a flag and rebuild your page instead of navigating to a new route.
Then, when building your BottomNavigationBarItemlist check the flag and add or remove BottomNavigationBarItem as you need.
Remove extra scaffold from _widgetOptions children that contains bottomNavBar. Follow the snippet pattern
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(home: TeamNav());
}
}
class TeamNav extends StatefulWidget {
const TeamNav({Key? key}) : super(key: key);
#override
State<TeamNav> createState() => _TeamNavState();
}
class _TeamNavState extends State<TeamNav> {
int _selectedIndex = 0;
final List<Widget> _widgetOptions = <Widget>[
Text("PlayersListView"),
Text(" GamesListView()"),
];
Widget? _onItemTap(int index) {
setState(() {
_selectedIndex = index;
});
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => CoachNav(),
));
}),
body: Container(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.group),
label: "Mes joueurs",
),
BottomNavigationBarItem(
icon: Icon(Icons.sports_basketball), label: "Mes matchs"),
],
currentIndex: _selectedIndex,
onTap: _onItemTap,
),
);
}
}
class CoachNav extends StatefulWidget {
const CoachNav({Key? key}) : super(key: key);
#override
State<CoachNav> createState() => _CoachNavState();
}
class _CoachNavState extends State<CoachNav> {
int _selectedIndex = 0;
final List<Widget> _widgetOptions = <Widget>[
Text("TeamListView"),
Text("SettingsFormView"),
];
Widget? _onItemTap(int index) {
setState(() {
_selectedIndex = index;
});
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: _widgetOptions.elementAt(_selectedIndex),
),
floatingActionButton: FloatingActionButton(onPressed: () {}),
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.groups),
label: "Mes équipes",
),
BottomNavigationBarItem(
icon: Icon(Icons.settings), label: "Paramètres"),
],
currentIndex: _selectedIndex,
onTap: _onItemTap,
),
);
}
}
Ok so I found a solution, I simply needed to add "rootNavigator: true" to my Navigator.push. It works as intended now.
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?
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",
),
),
),
);
}
}
I have a dart file with IndexedStack and the following function in the same file to change the stacks.
The file with method as follows-
class RootApp extends StatefulWidget with selectedTab {
#override
_RootAppState createState() => _RootAppState();
}
class _RootAppState extends State<RootApp> {
int pageIndex = 0;
List<Widget> pages = [
......
];
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
....
return AnimatedBottomNavigationBar(
.......
onTap: (index) {
selectedTab(index);
},
);
}
selectedTab(index) {
setState(() {
pageIndex = index;
});
}
}
There is this other dart file from which i would like to call selectedTab method with value of 0. The other file is as follows---
class CreatBudgetPage extends StatefulWidget {
#override
_CreatBudgetPageState createState() => _CreatBudgetPageState();
}
class _CreatBudgetPageState extends State<CreatBudgetPage> {
.......
FirebaseFirestore.instance
.collection('expenses/' + userId + '/' + todayDate)
.add({
....
}).then((_) {
print("collection created");
void rootApp() => selectedTab(0);
}).catchError((error) {
print(error);
});
}
How can i call this method from the other dart file?
P.S: I am a Newbie
You can pass the function callback as parameters from the source class to the intended class and invoke the function as you want.
here is a simple example.
class Example extends StatefulWidget {
const Example({Key? key}) : super(key: key);
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
int pageIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: IndexedStack(
index: pageIndex,
children: [
Tab1Page(),
Tab2Page(
/// solution 1
onPressed1: () {
selectedTab(0);
},
/// solution 2
// onPressed2: selectedTab,
),
],
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'TAB 1',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'TAB 2',
),
],
currentIndex: pageIndex,
selectedItemColor: Colors.amber[800],
onTap: selectedTab,
),
);
}
selectedTab(index) {
setState(() {
pageIndex = index;
});
}
}
class Tab1Page extends StatelessWidget {
const Tab1Page({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
child: Center(
child: Text(
"Tab1",
style: TextStyle(fontSize: 20),
),
),
);
}
}
class Tab2Page extends StatelessWidget {
final VoidCallback? onPressed1;
// final Function(int)? onPressed2;
const Tab2Page({
Key? key
/// solution 1
,
this.onPressed1,
/// solution 2
// this.onPressed2
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Tab2",
style: TextStyle(fontSize: 20),
),
ElevatedButton(
onPressed: () {
/// solution 1
if (onPressed1 != null) {
onPressed1!();
}
/// solution 2
// if(onPressed2!=null){
// onPressed2!(0);
//
// }
},
child: Text("click to navigate to another tab",
style: TextStyle(fontSize: 20)),
),
],
),
),
);
}
}
I am using a bottom navigation bar witch display a class according to the current index,
I used a ternary condition to check witch class to display on the first index using this code :
class Home extends StatefulWidget {
static String homeindex = "main";
#override
_HomeState createState() => _HomeState();
}
final greencol = HexColor("#2f7e7b");
class _HomeState extends State<Home> {
static int _currentindex = 0;
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
final tabs = [
(Home.homeindex == 'main') ? Homehome() : Green(),
Assistant(),
Profile(),
];
bottomNavigationBar: Container(
height: 55,
child: BottomNavigationBar(
currentIndex: _currentindex,
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.white,
selectedItemColor: greencol,
unselectedItemColor: Colors.grey,
selectedLabelStyle:
GoogleFonts.roboto(fontWeight: FontWeight.bold),
iconSize: 25,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home_outlined,
),
title: Text(
'Home',
),
),
BottomNavigationBarItem(
icon: Icon(
Icons.mic_outlined,
),
title: Text(
'Assistance',
),
),
BottomNavigationBarItem(
icon: Icon(
Icons.person_outlined,
),
title: Text(
'Profile',
),
),
],
onTap: (index) {
setState(() {
_currentindex = index;
});
},
),
)),
);
}
}
using a static string called home index I'm trying to change the display widget on the first index using set state from another class :
class Homehome extends StatefulWidget {
const Homehome({Key? key}) : super(key: key);
#override
_HomehomeState createState() => _HomehomeState();
}
class _HomehomeState extends State<Homehome> {
.....
child: ButtonTheme(
minWidth: 20.0,
height: 30.0,
child: RaisedButton(
onPressed: () {
setState(() {
Home.homeindex = 'greenhouse';
print(Home.homeindex);
});
},
but it's only setting state to the current class widget.
what's the easiest way to rebuild the widget from the last page ?
You need to bring your void callback from Homehome one level up to Home, then call setState to update the Home widget.
class Homehome extends StatefulWidget {
const Homehome({Key? key, required this.onPressedMyButton }) : super(key: key);
final VoidCallBack onPressedMyButton;
.....
child: ButtonTheme(
minWidth: 20.0,
height: 30.0,
child: RaisedButton(
onPressed: widget.onPressedMyButton,
In your Home widget:
.....
final tabs = [
(Home.homeindex == 'main') ? Homehome(onPressedMyButton: () {
setState(() {
Home.homeindex = 'greenhouse';
print(Home.homeindex);
});
}, ) : Green(),
Assistant(),
Profile(),
];
.....
I am trying to create a package where I add some functionality to a BottomNavigationBar. I want a generic helper that when used, wraps a bottom nav widget with another widget and changes its onTap method. Unfortunately, onTap is final and cannot be changed. This forces me to create the BottomNavigationBar widget in the package code. This results in me having to delegate all properties of the BottomNavigationBar from the user.
Ideally, I want the user to pass me a navigation bar instance, and I add the functionality to it as long as the passed in widget has currentIndex and onTap properties settable.
How would you solve this?
Edit
Code snippet for what I am trying to achieve:
class ExtendedBottomNav extends StatefulWidget {
const ExtendedBottomNav({required this.bottomNavBar});
final BottomNavigationBar bottomNavBar;
#override
State<StatefulWidget> createState() => ExtendedBottomNavState();
}
class ExtendedBottomNavState extends State<ExtendedBottomNav> {
int _currentTabIndex = 0;
#override
Widget build(BuildContext context) {
widget.bottomNavBar.currentIndex = _currentTabIndex;
widget.bottomNavBar.onTap = (int index) => {
// Some code, using _currentTabIndex
};
return Scaffold(
body: Text("Text"), // Some body
bottomNavigationBar: widget.bottomNavBar,
);
}
}
This is not possible because 'onTap' can't be used as a setter because it's final.
You can use this approach (uses null safety). I've not used all the constructor parameters, you can modify as per your need.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: CustomBottomNavigationBar(bar:BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
));
}
}
class CustomBottomNavigationBar extends StatelessWidget {
final BottomNavigationBar bar;
CustomBottomNavigationBar({ required this.bar});
BottomNavigationBar? customBar;
#override
Widget build(BuildContext context) {
customBar = BottomNavigationBar(
items: bar.items,
currentIndex: bar.currentIndex,
selectedItemColor: bar.selectedItemColor,
onTap: (int index){
// here you can add your additional code
print("hi");
if(bar.onTap != null)
bar.onTap!(index);
},
);
return Container(
child:customBar);
}
}
Without null safety
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: CustomBottomNavigationBar(bar:BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
));
}
}
class CustomBottomNavigationBar extends StatelessWidget {
final BottomNavigationBar bar;
CustomBottomNavigationBar({ #required this.bar});
BottomNavigationBar customBar;
#override
Widget build(BuildContext context) {
customBar = BottomNavigationBar(
items: bar.items,
currentIndex: bar.currentIndex,
selectedItemColor: bar.selectedItemColor,
onTap: (int index){
print("hi");
if(bar.onTap != null)
bar.onTap(index);
},
);
return Container(
child:customBar);
}
}
i think you can do it by extending the BottomNavigationBar widget and override
the onTap funtion and tell user to pass the new subclass of BottomNavigationBar
class NewBottomNavigationBar extends BottomNavigationBar {
NewBottomNavigationBar(List<BottomNavigationBarItem> items)
: super(items: []);
#override
ValueChanged<int>? onTap;
}