I am struggling making a FAB move up when a snackbar is showing.
Here is my set up.
I have my main page with a bottom navigation bar with 3 items.
The first item is basically a widget with a ListView and a floating action button.
Once you click an item of the list view, you navigate to a details page. If you then delete the item from the details page, you come back to the main page.
A snackbar then appears as a result from deleting the item.
The problem I have is that the snack bar is not moving up and hides the FAB.
It assumes it has something to do with context, but I don't know how.
If I move the FAB to the main page, the FAB goes up but it then hides last item of the listview.
Page with list view and FAB:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
title,
style: Theme.of(context).textTheme.titleMedium,
),
),
body: WidgetWithListView(),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
//do something
},
label: Text('label'),
icon: const Icon(Icons.add),
));
}
Main page:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(appBarTitle,
style: Theme.of(context)
.textTheme
.titleLarge!
.copyWith(fontWeight: FontWeight.bold)),
actions: <Widget>[
IconButton(
icon: const Icon(some icon),
tooltip: 'some tooltip',
onPressed: () {
//do something;
},
),
]),
body: Center(
child: getBody(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: const Icon(someIcon),
label: 'a label'y,
),
BottomNavigationBarItem(
icon: const Icon(someIcon),
label: 'a label',
),
BottomNavigationBarItem(
icon: const Icon(someIcon),
label: 'a label',
),
],
currentIndex: _selectedIndex,
type: BottomNavigationBarType.fixed,
onTap: _onItemTapped,
),
);
}
Thanks.
Related
I would like to set whether to show the bottom navigation bar in a Flutter app page/screen/route by route. For example, when the user navigates through their files and clicks on folders, I want to show the bottom navigation bar. But when the user clicks on a "Create" button, I would not like the bottom navigation for the rest of this flow, and the user navigates backward through the back button in the app bar.
If this is not possible without a very customized, hacky, inflexible, complication solution, I would also be fine with choosing at the beginning of the flow whether to remove the bottom navigation bar.
I have tried the "normal" method, in which the bottom navigation bar only stays for the buttons that are in the bar itself, and it does not persist for anything else (using an IndexedStack and a _currentIndex variable). I have also tried the opposite, in which the bottom navigation shows for everything, which is also not desirable.
Here's what I have currently:
MyApp top-level widget:
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flytrap Audio',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const CurrentPage(),
);
}
CurrentPageState (stateful) Widget
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: screens,
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
showUnselectedLabels: false,
currentIndex: _currentIndex,
onTap: (index) {
// debugPrint("index: $index");
setState(() => _currentIndex = index);
// _navigatorKey.currentState!
// .pushNamedAndRemoveUntil(screens[index], (route) => false);
// debugPrint("Navigated to ${screens[index]}");
},
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.folder),
label: 'Files',
),
BottomNavigationBarItem(
icon: Icon(Icons.live_tv),
label: 'Live Broadcasts',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
),
],
),
);
}
And each page, like FolderPage is a Scaffold
I think you can check my code, I do the little same as you said.But I use the PageView instead:
final _listPage = [
const Page1(),
const Page2(),
const Page3(),
const Page4()
];
final _controller = PageController();
int _indexSelected = 0;
void _onSelected(int index) {
setState(() {
_indexSelected = index;
});
}
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: _controller,
onPageChanged: _onSelected,
children: _listPage,
),
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(
icon: ImageIcon(
AssetImage('assets/images/bottom_tab/bw_u.png'),
size: 25,
),
label: 'Item 0'),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_bag), label: 'Item 1'),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle_outlined), label: 'Item 2'),
BottomNavigationBarItem(icon: Icon(Icons.widgets), label: 'Item 3')
],
currentIndex: _indexSelected,
onTap: (index) => _controller.animateToPage(index,
duration: const Duration(milliseconds: 200), curve: Curves.easeIn),
selectedItemColor: const Color.fromARGB(255, 38, 112, 205),
unselectedItemColor: Colors.grey,
type: BottomNavigationBarType.fixed,
),
);
}
I am new at Flutter. I started a new project regarding social media. I used BottomTabNavigation for navigating the Home screen to the notification screen. Now the problem is that when I am showing feeds on the home page and I scroll down at many posts. let's say I am on post number 50. Now when I click on the notification and again click on the Home page its started from begin. I need to stay my scroll at a previous position on every main screen.
Here is my code for navigating one page to another.
class _DefaultLayoutWidgetState extends State<DefaultLayoutWidget> {
final List<Map<String, dynamic>> _pages = [
{'page': PostScreen(), 'title': 'SelfieCorner'},
{'page': NotificationScreen(), 'title': 'Notifications'}
];
int _curruntIndex = 0;
void handleTapEvent(inx) {
setState(() {
_curruntIndex = inx;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PostAppBarWidget(),
body: _pages[_curruntIndex]['page'],
bottomNavigationBar: BottomNavigationBar(
onTap: (index) => handleTapEvent(index),
currentIndex: _curruntIndex,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(
Icons.notifications,
),
title: Text('Notifications'),
),
BottomNavigationBarItem(
icon: Icon(
Icons.lock,
),
title: Text('Profile'),
)
],
),
);
}
}
Consider using IndexedStack like this. It will save the state of the previous widget while moving to another.
body: IndexedStack(.....),
bottomNavigationBar: BottomNavigationBar(
onTap: (index) => handleTapEvent(index),
currentIndex: _curruntIndex,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(
Icons.notifications,
),
title: Text('Notifications'),
),
BottomNavigationBarItem(
icon: Icon(
Icons.lock,
),
title: Text('Profile'),
)
],
),
IndexedStack Widget Video
Tutorial on medium
I am making an app in which I have to pages, routed by a BottomNavigationBar, and each page has its own nested routes. The app contains a main FloatingActionButton centered and docked into the BottomNavigationBar. The problem is that I wanted to control what the FAB does from inside each nested route. The problem is that if I create a FAB inside each nested route the button will not be docked into the BottomNavigationBar. Bellow are some pictures. Anyone can help? Thanks in advance.
What I have :
What I wanted :
Is this what you are asking? If not please share some code which casing the problem
UPDATE
Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: _screenList[_screenIndex],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _screenIndex,
onTap: (index) {
print(index);
setState(() {
_screenIndex = index;
});
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.inbox),
title: Text('Screen1'),
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text('Screen2'),
),
]),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.android,
),
onPressed: () {
_screenIndex == 0
? print('hello from screen1')
: print('hello from screen2');
},
),
);
OUTPUT
I have a navigation_bar.dart file that handles changing to new pages within my app. Within it, I am using the bottomNavigationBar to build out four different pages based on what tab is currently selected like so:
class NavigationBar extends StatefulWidget {
#override
_NavigationBarState createState() => _NavigationBarState();
}
class _NavigationBarState extends State<NavigationBar> {
int _selectedIndex = 0;
final List<Widget> _pageOptions = <Widget>[
Page1(),
Page2(),
Page3(),
Page4(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
String userID =
Provider.of<FirebaseUser>(context, listen: false) != null ? Provider.of<FirebaseUser>(context).uid : 'null';
return MultiProvider(
providers: [StreamProvider<MyUser>.value(value: DatabaseService().streamUser(userID))],
child: Scaffold(
body: IndexedStack(
children: _pageOptions,
index: _selectedIndex,
),
bottomNavigationBar: Theme(
data: Theme.of(context).copyWith(
canvasColor: Color(0xff271037).withOpacity(0.90),
splashColor: Colors.transparent,
),
child: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: _onItemTapped,
unselectedItemColor: Colors.white,
selectedItemColor: Color(0xff3ADEA7),
type: BottomNavigationBarType.fixed,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Container(),
title: Icon(FontAwesomeIcons.fire, color: Colors.white),
),
BottomNavigationBarItem(
icon: Container(),
title: Icon(Icons.fastfood, color: Colors.white),
),
BottomNavigationBarItem(
icon: Container(),
title: Icon(Icons.directions_bike, color: Colors.white),
),
BottomNavigationBarItem(
icon: Container(),
title: Icon(Icons.person, color: Colors.white),
)
],
),
),
),
);
}
}
Now, in a different file which is Page3.dart, on that page there is an alert dialog that pops up and when clicked, I want it to navigate to Page4().
Future<void> _showMissingDataDialog(String data) async {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('You have not set your $data yet.'),
actions: <Widget>[
FlatButton(
splashColor: Colors.transparent,
highlightColor: Colors.grey[200],
textColor: Colors.black,
child: const Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
FlatButton(
splashColor: Colors.transparent,
highlightColor: Colors.grey[200],
textColor: Colors.black,
child: Text('Set $data', style: TextStyle(fontWeight: FontWeight.bold)),
onPressed: () {
Navigator.of(context).pop();
// TODO: Redirect to page4() here as if it was tapped on the BottomNavigationBar
})
],
);
},
);
}
How can I have it so that clicking the "Set $data" button would route to Page4()? I want to make it so that the bottomNavigationBar reacts to this as if you tapped on the actual fourth BottomNavigationBarItem item.
Give your Nav Bar a Global Key. I declared this outside of all widgets on my main Dart file.
GlobalKey navBarGlobalKey = GlobalKey(debugLabel: 'bottomAppBar');
bottomNavigationBar: BottomNavigationBar(
key: navBarGlobalKey,
onTap: _onItemTapped,
currentIndex: _selectedIndex,
type: BottomNavigationBarType.fixed,
items: [ ... ]
Then use the global key to call the onTap Method in the onPressed method of your button. You will have to import the other dart file into this page before the global key is available.
final BottomNavigationBar navigationBar = navBarGlobalKey.currentWidget;
initialIndex = 0;
navigationBar.onTap(3); //Starts at index 0, so passing in 3 should do the trick.
I am new in flutter. I am trying to create a main screen where there is bottom bar with floating action button(FAB). The fab is docked at the center of bottom app bar. Meanwhile, the bottom app bar has 4 bottom navigation items. Currently all the items are not perfectly aligned with each other. The search and notification icons are too close to the center. Is there a way i can arrange it to make it better and perfectly aligned? Please help. Thank you
Current ui:
The code:
import 'package:flutter/material.dart';
class Dashboard extends StatefulWidget {
_DashboardState createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
int _selectedPage = 0;
final _pageOptions = [
Home(),
Discover(),
Notifications(),
Messages(),
];
Widget build(BuildContext context) {
final _drawerNav = Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(color: colorPrimary),
),
ListTile(
title: Text('Item 1'),
onTap: () {},
),
Divider(),
ListTile(
title: Text('Item 2'),
onTap: () {},
),
Divider(),
],
),
);
final _bottomNav = BottomAppBar(
shape: CircularNotchedRectangle(),
notchMargin: 6,
clipBehavior: Clip.antiAlias,
child: BottomNavigationBar(
selectedItemColor: colorPrimary,
unselectedItemColor: Colors.grey,
currentIndex: _selectedPage,
onTap: (int index) {
setState(() {
_selectedPage = index;
});
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home), title: Container(height: 8.0)),
BottomNavigationBarItem(
icon: Icon(Icons.search), title: Container(height: 8.0)),
BottomNavigationBarItem(
icon: Icon(Icons.notifications), title: Container(height: 8.0)),
BottomNavigationBarItem(
icon: Icon(Icons.message), title: Container(height: 8.0)),
],
),
);
final _fab = FloatingActionButton(
child: Icon(Icons.add),
backgroundColor: colorPrimary,
onPressed: () {},
);
return Scaffold(
appBar: AppBar(
title: Text('Test'),
backgroundColor: colorPrimary,
),
drawer: _drawerNav,
body: _pageOptions[_selectedPage],
floatingActionButton: _fab,
bottomNavigationBar: _bottomNav,
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
I made a quick and dirty fix
I made the bottom navigation bar using row. Instead of using 4 children, I use 5. One of them is a dummy child
https://gist.github.com/hariangr/2739c25dda72edcbc18073b907ef057a
Try setting type in BottomNavigationBar to BottomNavigationBarType.fixed
The bottom navigation bar's type changes how its items are displayed. If not specified, then it's automatically set to BottomNavigationBarType.fixed when there are less than four items, and BottomNavigationBarType.shifting otherwise.
BottomNavigationBarType.fixed, the default when there are less than four items. The selected item is rendered with the selectedItemColor if it's non-null, otherwise the theme's ThemeData.primaryColor is used. If backgroundColor is null, The navigation bar's background color defaults to the Material background color, ThemeData.canvasColor (essentially opaque white).
BottomNavigationBarType.shifting, the default when there are four or more items. If selectedItemColor is null, all items are rendered in white. The navigation bar's background color is the same as the BottomNavigationBarItem.backgroundColor of the selected item. In this case it's assumed that each item will have a different background color and that background color will contrast well with white.