What is the best way to do the bottom navigation bar in flutter?
According to Getting to the Bottom of Navigation in Flutter the flutter team used IndexedStack
with Offstage
to show the widget when the user changes the tab, but I see there's another way of doing this by TabBarView
to change between widgets with simple slide animation and also keeping each widget's scroll state
So what's the difference between the IndexedStack
+ Offstage
and TabBarView
? and what is the best way to change the current tab should I use something like flutter_bloc
or just use setState()
?
Well, there are many ways to implement BottomNavigationBar
in Flutter.
But Using the IndexedStack
method would create all the screens of theBottomNavigationBar
at the starting. This can be fixed using TabBarView
.
Here's how I Implemented BottomNavigationBar
in my app using CupertinoTabBar
and PageView
as it would make only one screen at the starting. And also using AutomaticKeepAliveMixin
as it wouldn't let the screens to be recreated again.
PageView
with PageController
by which you can easily shift between screens.AutomaticKeepAliveClientMixin
doesn't let the screens to be recreated and thus there is no need to use IndexedStack
.Provider
and Consumer
to recreate only the CupertinoTabBar
when changing the currentIndex
. Instead of using setState()
, as it would recreate the whole screen letting all the widgets to get rebuild. But here were are using Provider
to recreate only TabBar
.HomePage (
BottomNavigtionBar
)
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
PageController _pageController;
@override
void initState() {
_pageController = PageController();
super.initState();
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
// Wrapping the CupertinoTabBar in Consumer so that It only get
// recreated.
bottomNavigationBar: Consumer<HomeVM>(
builder: (context, model, child) {
return CupertinoTabBar(
backgroundColor: Colors.white10,
currentIndex: model.currentPage,
onTap: (index) {
index == model.currentPage
? print('same screen')
: _pageController.jumpToPage(
index,
);
model.changePage(index);
},
items: bottomNavItems);
},
),
body:ChangeNotifierProvider(
create: (_) => locator<HelpVM>(),
child: SafeArea(
top: false,
child: PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(),
children: <Widget>[
FrontScreen(),
WorkRootScreen(),
HelpScreen(),
AccountScreen(),
],
),
),
),
);
}
const List<BottomNavigationBarItem> bottomNavItems =
<BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: const Icon(
FontAwesomeIcons.home,
),
),
//...... bottomNavigationBarItems
];
}
HomeVM (Using
Provider
to change the index and recreate onlyTabBar
usingConsumer
)
class HomeVM extends ChangeNotifier {
int _currentPage = 0;
int get currentPage => _currentPage;
void changePage(int index) {
this._currentPage = index;
notifyListeners();
}
}
FrontScreen (Here we are using
AutomaticKeepAliveClientMixin
to retain the state by not recreating the Widget)
class FrontScreen extends StatefulWidget {
@override
_FrontScreenState createState() => _FrontScreenState();
}
class _FrontScreenState extends State<FrontScreen>
with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
// VIMP to Add this Line.
super.build(context);
return SafeArea(
// Your Screen Code
);
}
@override
bool get wantKeepAlive => true;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With