In fluter, I have 2 tab pages that show different view. I wanted to have the floatingactionbutton to show only in one of the view and hidden in other tabs.
But the floatingactionbutton stays floating even when the view is switched.
Can anyone help me on this? If there is any code or tutorial, it would be appreciated.
demo pic:
tab1 show fab
tab2 hide fab
You can set floatingActionButton to null when _selectedIndex == 0, then FAB is gone with animation, so cool. And remember to change _selectedIndex in BottomNavigationBar onTap method.
Here is the example code with some comments:
final _tabTitle = [
'Title 1',
'Title 2'
]; // BottomNavigationBarItem title
final _tabIcon = [
Icon(Icons.timer_off),
Icon(Icons.timeline),
]; // BottomNavigationBarItem icon
class _MyHomePageState extends State<MyHomePage> {
int _selectedIndex = 0;
String title = _tabTitle[0];
// tap BottomNavigationBar will invoke this method
_onItemTapped(int index) {
setState(() {
// change _selectedIndex, fab will show or hide
_selectedIndex = index;
// change app bar title
title = _tabTitle[index];
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(title),
),
body: Center(
child: Text(_tabTitle[_selectedIndex]),
),
// two tabs
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(title: Text(_tabTitle[0]), icon: _tabIcon[0]),
BottomNavigationBarItem(title: Text(_tabTitle[1]), icon: _tabIcon[1])
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
// key point, fab will show in Tab 0, and will hide in others.
floatingActionButton: _selectedIndex == 0 ? FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
) : null,
);
}
}
You can create a list of FloatingActionButtons for each page.
Call index method on the TabController variable to know the index of the tab that is active and use that to select a fab from the list.
Don't forget to call addListener on the TabController variable.
here is snippet code of how I did it:
// in the main statefulwidget class
TabController tabController;
var fabIndex;
#override
void initState() {
super.initState();
tabController = new TabController(length: 3, vsync: this,initialIndex: 0);
tabController.addListener(_getFab);
fabIndex=0;
}
void dispose() {
tabController.dispose();
super.dispose();
}
final List<FloatingActionButton> fabs=[
new FloatingActionButton(child: new Icon(Icons.access_time),onPressed: (){},),
new FloatingActionButton(child: new Icon(Icons.account_balance),onPressed: (){},),
new FloatingActionButton(child: new Icon(Icons.add_alert),onPressed: (){},)
];
void _getFab(){
setState((){`enter code here`
fabIndex=tabController.index;
});
}
Use the fabIndex in the scaffold's floatingActionButton property as follows:
floatingActionButton: fabs[fabIndex],
I would wrap the tab you want with a scaffold and give it a fab.
TabBarView(
children:[
Text("tab1"),
Scaffold(body:Text("tab2"),
floatingActionButton: FloatingActionButton(...)
)
)
The easiest way is to just give your each tab it's own Scaffold as the top widget, and provide it's own FAB there (Instead of the Scaffold where each tabs are kept, the main Scaffold, place it individually inside every tab's Scaffold, and remove from the top Scaffold). If you already have one, you can wrap it inside another. But if you want to keep the FAB the same in every other screen except some, you then can follow other solutions written here.
Related
I have a bottom navigation bar with 4 tabs; Home, Loans, Insurance and Settings. The Settings page has buttons leading to many other pages but those pages are not supposed to be on the navigation bar. However the navigation bar needs to persist across all the pages to make it easy to go back to the main pages like the Home Page. Below is the code for my bottom navigation bar:
import 'package:bima/Insurance/insurance.dart';
import 'package:bima/Loans/loans.dart';
import 'package:bima/Settings/settings.dart';
import 'package:flutter/material.dart';
import '../Home/home.dart';
class Dashboard extends StatefulWidget {
const Dashboard({Key? key}) : super(key: key);
#override
_DashboardState createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
int _currentIndex = 0;
final tabs = [
const Home(),
const Loans(),
const Insurance(),
const Settings()
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: tabs[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
unselectedItemColor: Colors.black,
selectedItemColor: const Color.fromRGBO(212, 164, 24, 1),
currentIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.wallet_outlined),
label: 'Loans',
),
BottomNavigationBarItem(
icon: Icon(Icons.shield_moon_outlined),
label: 'Insurance',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
),
],
),
);
}
}
This is a picture of the pages with a navigation bar and the pages without:
How can I make sure the navigation bar appears and works across all the pages without having to add extra tabs to the index? Edit: The code I have posted works so far for navigating the pages in the index namely: Home, Loans, Insurance and Settings. I do not want to add any other pages to the index, I would just like to display the navigation bar on the other pages which are not included in the index.
1 - Take a look at this package: https://pub.dev/packages/google_nav_bar.
2 - check that your bottom nav is implemented in the right place.
Instead of using BottomNavigationBar use TabBar it has controller that can be used.
First initialize _tabController in init
late TabController _tabController;
void initState() {
super.initState();
_tabController = TabController(length: 2, initialIndex: 0, vsync: this);
//_tabController.addListener(_handleTabChange);
}
void _handleTabChange() async {
//controller handel tab change by default so no need to handle it here
//this is anything custom you want to perform when tab is changed
}
final tabIcons = [
// Homeicon,
// Loansicon,
// Insuranceicon,
// Settingsicon
];
bottom: TabBar(
controller: _tabController,
indicatorColor: Colors.red,
tabs: tabIcons
),
And in body use with list of tabs as you declared above
TabBar(
controller: _tabController,
indicatorColor: Colors.red,
tabs: tabs, //list of tabs as you declared already use here a
),
And if you want to continue on with BottomNavigationBar follow below instructions
It might not be optimal solution but it was working for me and hope so it will also work for you, on navigating use Navigator.pushReplacement if you don't want to navigate back to last page visited, and if you want to navigate to previous page on back press use simple Navigator.push
onTap use this instead of only updating current index
onTap: (index) {
setState(() {
_currentIndex = index;
});
goToIndexPage(index);
},
goToIndexPage(int index) {
if (index == 0) {
//navigate to 1st
// Navigator.pushReplacement(
// context,
// MaterialPageRoute(builder: (context) => const Home()),
// );
} else if (index == 1) {
//navigate to 2nd page
// Navigator.pushReplacement(
// context,
// MaterialPageRoute(builder: (context) => const Loan()),
// );
} else if (index == 2) {
//navigate to 3rd page
} else if (index == 3) {
//navigate to 4th page
}
}
I am working on the bottom navigation bar feature. I have 4 screens associated with a bottom navigation bar.
Page1 Index0 (It has a button)
Page2 Index1
Page3 Index2
Page4 Index3
Each click on the bottom icon will change the index of a bottom navigation bar and triggers the specific screen to load.
Now I want to click on the button of screen 1 which is index 0 of a bottom navigation bar, this should make a call to load page2 as if I select the second icon of a bottom navigation bar.
I tried using the navigator.push(context,page()) which loaded the page however the bottom navigation bar was not visible. This is not the way, Is there any way to do it correctly?
Thanks
Use IndexedStack widget for this. Example is as follows:
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _currentIndex = 0; //Current selected index of the bottom navigation bar tab
void changeTab(int index) {
setState(() => _currentIndex = index);
}
#override
Widget build(BuildContext context) {
//List of Screens that you want to put
final screens = [
const Screen1(),
const Screen2(),
const Screen3(),
];
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: screens,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) => changeTab(index),
type: BottomNavigationBarType.fixed,
unselectedItemColor: Colors.grey,
selectedItemColor: Colors.red,
showUnselectedLabels: false,
showSelectedLabels: false,
iconSize: 20,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.foo),
label: 'Screen1',
),
BottomNavigationBarItem(
icon: Icon(Icons.bar),
label: 'Screen2',
),
BottomNavigationBarItem(
icon: Icon(Icons.baz),
label: 'Screen3',
),
],
),
);
}
}
I fixed this issue using a Provider. The issue has been resolved now.
I've read your question and that's what I found out:
You want to change the bottom navigation bar pages by clicking on a button.
To do so, simply change the index variable that you are passing to the selected index of the bottom navigation to the index of the page you want, and you will need to make it inside a setState function so the variable get updated.
Like the code below:
onTap: () {
setState((() => this.index = 0));
},
You can change bottom navigation bar index from every screen
static int bottomNavigationTabIndex = 0;
static void selectPage(BuildContext context,int index) {
BottomNavigationScreenState? stateObject = context.findAncestorStateOfType<BottomNavigationScreenState>();
stateObject?.setState((){
bottomNavigationTabIndex = index;
});
}
I am using the flutter_pagewise library and have implemented a paginated grid as per the library's documentation (following their example at https://pub.dev/packages/flutter_pagewise/example), which grabs placeholder images and text via the network.
In my app, I have 2 pages (one is called PaginatedGrid and the other is called SearchPage) that I can tab to via a BottomNavigationBar. However, when I tab to the SearchPage, then tab back to PaginatedGrid, the paginated grid scroll state isn't preserved. The pagination starts from the very beginning and the screen is scrolled back to the top.
import 'package:myproject/my_events/my_events_page.dart';
import 'package:myproject/search/search_page.dart';
import 'package:myproject/widget/paginated_grid.dart';
import 'package:flutter/material.dart';
class PageWrapper extends StatefulWidget {
#override
_PageWrapperState createState() => _PageWrapperState();
}
class _PageWrapperState extends State<PageWrapper> {
ScrollController _scrollController = ScrollController();
int _curIndex = 0;
List<Widget> _pages;
final bucket = PageStorageBucket();
final Key searchPageKey = PageStorageKey('searchKey');
final Key paginatedGridKey = PageStorageKey('paginatedGrid');
#override
void initState() {
_pages = [
PaginatedGrid(key: paginatedGridKey),
SearchPage(key: searchPageKey)
];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageStorage(
bucket: bucket,
child: CustomScrollView(
key: PageStorageKey(_pages[_curIndex].runtimeType.toString()),
controller: _scrollController,
slivers: <Widget>[SliverAppBar(), _pages[_curIndex]],
),
),
bottomNavigationBar: BottomNavigationBar(
onTap: (int i) {
setState(() {
_curIndex = i;
});
},
currentIndex: _curIndex,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Browse',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
)
],
),
);
}
}
Any help would be appreciated.
Using an indexedStack is a solution that worked! The paginated state is preserved on navigation to another tab from the bottom navigation bar.
Instead of using a PageStorage widget, use an IndexedStack widget.
#override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: currentTab,
children: pages,
),
bottomNavigationBar: BottomNavigationBar(
The solution is described here: https://medium.com/#codinghive.dev/keep-state-of-widgets-with-bottom-navigation-bar-in-flutter-bb732214bd11
I'm working on a project with flutter, I have a bottom navigation bar , this bar allow me to move on different scenes . I would like to remove my bottom navigation bar when i navigate to a detail page, there is any method? I'm trying all the possible solution , but i can't solve the problem, maybe i've implemented wrong my navigation bar !
Some Code:
My HomePage where i implemented the bottom navigation bar and where i call all the others pages:
class homeScreen extends StatefulWidget {
#override
_homeScreenState createState() => _homeScreenState();
}
class _homeScreenState extends State<homeScreen> {
TextEditingController _linkController;
int _currentIndex = 0;
final _pageOptions = [
meetingScreen(),
dashboardScreen(),
notificationScreen(),
profileScreen(),
];
#override
void initState() {
// TODO: implement initState
super.initState();
_linkController = new TextEditingController();
}
#override
Widget build(BuildContext context) {
ScreenUtil.instance = ScreenUtil(width: 1125, height: 2436)..init(context);
return MaterialApp(
title: myUi.myTitle,
theme: myUi.myTheme ,
debugShowCheckedModeBanner: false,
home:Scaffold(
bottomNavigationBar: _buildBottomNavigationBar(),
body: _pageOptions[_currentIndex] ,
) ,
);
}
Widget _buildBottomNavigationBar() {
return BottomNavigationBar(
backgroundColor: Colors.white,
selectedItemColor: Theme.of(context).primaryColor,
//fixedColor: gvar.secondaryColor[gvar.colorIndex],
currentIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.explore,size: ScreenUtil().setWidth(80),),
title: new Text("Esplora"),
),
BottomNavigationBarItem(
icon:Icon(Icons.dashboard,size: ScreenUtil().setWidth(80),),
title: new Text("Attività "),
),
BottomNavigationBarItem(
icon:Icon(Icons.notifications,size: ScreenUtil().setWidth(80),),
title: new Text("Notifiche"),
),
BottomNavigationBarItem(
icon:Icon(Icons.person,size: ScreenUtil().setWidth(80),),
title: new Text("Profilo"),
),
],
);
}
}
This is the code i use into the dashboardScreen to push to my detail page:
onTap: () {
//method: navigate to Meeting
Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) => new meetingScreen()),
);
},
In the new meetingScreen i have some ui , but i cant remove my old bottom navigation bar, i tried implementing a new navigation bar but it isn't displayed.
A partial working solution was to do like so:
Navigator.of(context, rootNavigator: true).pushReplacement(MaterialPageRoute(builder: (context) => new meetingScreen()));
But now I can't do Navigator.pop with the cool animation , because the new page is the root!
Thanks guys for the support !!
To navigate to a different screen without the bottom Navigation bar, you'd need to call Navigator.push() from _homeScreenState. For you to be able to do this, you need to create a NavigatorKey in _homeScreenState and set it in MaterialApp().
final _mainNavigatorKey = GlobalKey<NavigatorState>();
...
MaterialApp(
navigatorKey: _mainNavigatorKey,
...
)
You can then pass the NavigatorKey to your pages. To use _mainNavigatorKey, fetch its current state to be able to invoke push().
navigatorKey.currentState!.push(...)
Here's a sample that I have. Though instead of a bottom Navigation bar, I'm using a Navigation Drawer. The same method applies in this sample.
I would like to be able to change the navigation bar tab programmatically. I have a button inside Page1 that navigates to Page2. When I perform this, the navigation bar disappears because I didn't select page2 using the navigation bar.
I have 4 dart files along the lines of navigationbar.dart, page1.dart, page2.dart, page3.dart
The Navigation page is the home page of the application with the children:
final List<Widget> _children = [
Page1(),
Page2(),
Page3(),
];
return Scaffold(
backgroundColor: Colors.black,
body: _children[_selectedPage],
bottomNavigationBar: _bottomNavigationBar(context),
resizeToAvoidBottomPadding: true,
);
You have to change a TabControlller like this
1* Create TabController instance
TabController _tabController;
2* in initState methode use this
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 3);
}
3* add a Mixin to _HomeState
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {....}
4* assign the TabController to your TabBar
TabBar(
controller: _tabController,
tabs: _yourTabsHere,
),
5* Pass controller to your Pages
TabBarView(
controller: _tabController,
children:<Widget> [
Page1(tabController:_tabController),
Page2(tabController:_tabController),
Page3(tabController:_tabController),
];
6* call tabController.animateTo() from Page1
class Page1 extends StatefulWidget {
final TabController tabController
Page1({this.tabController});
....}
class _Page1State extends State<Page1>{
....
onButtonClick(){
widget._tabController.animateTo(index); //index is the index of the page your are intending to (open. 1 for page2)
}
}
Hope it helps
You can do that using a GlobalKey.
var bottomNavigatorKey = GlobalKey<State<BottomNavigationBar>>();
put that key in widget,
new BottomNavigationBar(
key: bottomNavigatorKey,
items: [...],
onTap: (int index) {...},
),
put below lines in change tab method,
BottomNavigationBar navigationBar = bottomNavigatorKey.currentWidget as BottomNavigationBar;
navigationBar.onTap(1);
in the button :
onPressed: (){
_currentIndex = 1;
//or which value you want
setState((){});
}
in the bottom Navigation bar :
currentIndex = _currentIndex
You can Use IndexStack.
Demostration.