Flutter: Persistent BottomAppBar and BottomNavigationBar - flutter

I am new to flutter, and I am building an app that has BottomAppBar which takes the property bottomNavigationBar: of Scaffold() for my home_screen, because I needed it to be at the bottom of the screen and persistent throughout the pages, and I also need a BottomNavigationBar to be persistent also at the top of BottomAppBar, but I can't make that happen because BottomAppBar already takes the bottomNavigationBar: property.
How can I make my BottomNavigationBar persistent alongside my BottomAppBar?
Note: I am using PageView() to scroll through my pages and it will be controlled by the BottomNavigationBar
Edit: attached here is the UI that I am trying to achieve
code snippet:
import 'package:flutter/material.dart';
//screens
import 'package:timewise_flutter/screens/calendar_screen.dart';
import 'package:timewise_flutter/screens/covey_quadrants_screen.dart';
import 'package:timewise_flutter/screens/kanban_screen.dart';
import 'package:timewise_flutter/screens/todo_list_screen.dart';
class OverviewScreen extends StatefulWidget {
static const String id = 'overview_screen';
//const OverviewScreen({Key? key}) : super(key: key);
#override
_OverviewScreenState createState() => _OverviewScreenState();
}
class _OverviewScreenState extends State<OverviewScreen> {
PageController _pageController = PageController(initialPage: 2);
int _bottomNavBarCurrentIndex = 2;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
bottomNavigationBar: SafeArea(
child: BottomAppBar(
elevation: 16.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
tooltip: 'Menu',
icon: Icon(Icons.menu_rounded),
onPressed: () {
print('menu icon pressed!');
//TODO: show bottom modal bottom sheet
},
),
IconButton(
tooltip: 'Pomodoro Timer',
icon: Icon(Icons.hourglass_empty_rounded),
onPressed: () {
print('pomo icon pressed!');
//TODO: show pomodoro timer modal bottom sheet
},
),
IconButton(
tooltip: 'Add',
icon: Icon(Icons.add_circle_outline_outlined),
onPressed: () {
print('add icon pressed!');
//TODO: show add task modal bottom sheet
},
),
],
),
);,
),
body: PageView(
controller: _pageController,
onPageChanged: (page) {
setState(() {
_bottomNavBarCurrentIndex = page;
});
},
children: [
CalendarScreen(),
ToDoListScreen(),
SafeArea(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('Overview Screen'),
BottomNavigationBar(
currentIndex: _bottomNavBarCurrentIndex,
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.white,
elevation: 0.0,
iconSize: 16.0,
selectedItemColor: Colors.black,
unselectedItemColor: Colors.grey,
showSelectedLabels: false,
showUnselectedLabels: false,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today_rounded),
label: 'Calendar',
tooltip: 'Calendar',
),
BottomNavigationBarItem(
icon: Icon(Icons.checklist_rounded),
label: 'To-Do',
tooltip: 'To-Do List',
),
BottomNavigationBarItem(
icon: Icon(Icons.panorama_fish_eye_rounded),
label: 'Overview',
tooltip: 'Overview',
),
BottomNavigationBarItem(
icon: Icon(Icons.border_all_rounded),
label: 'Covey\'s 4 Quadrants',
tooltip: 'Covey\'s 4 Quadrants',
),
BottomNavigationBarItem(
icon: Icon(Icons.view_column_rounded),
label: 'Kanban Board',
tooltip: 'Kanban Board',
),
],
onTap: (index) {
setState(() {
_bottomNavBarCurrentIndex = index;
_pageController.jumpToPage(index);
});
},
),
],
),
),
),
CoveyQuadrantsScreen(),
KanbanScreen(),
],
),
);
}
}

Unfortunately, this is not a standard way in which the mobile app UI should be designed. This will result in bad user experience.
What if user accidently touches on NavigationBar instead of
AppBar. You will be taken to the new screen and action that I
performed there will be lost or need to handle.
So proper UI guidelines should be met, while we design and develop for the mobile app. Based on guidelines from material.io
Bottom app bars should be used for:
Mobile devices only
Access to a bottom navigation drawer
Screens with two to five actions
Bottom app bars shouldn't be used for:
Apps with a bottom navigation bar
Screens with one or no actions
Refer this link for more useful information about the UI and UX guidelines https://material.io/

I would suggest making a scaffold() with the bottomNavigationBar() as you did. Then you could create a list of Container() objects each representing a different page. For your PageView I'm assuming you have done that, if not then that's the way to do it. Then you could cycle through your pages by setting the body: property of the scaffold to myPages[_currentIndex] or something like that.
Additionally: Like the comment asks, I am also not sure why you would want both BottomNavigationBar and BottomAppBar they both do exactly the same thing. In either case the process is the same as what I described above.

Related

Flutter - How to position snackbar above system navigation bar

I have a transparent system navigation bar in my application.
Getx snack bar is used by the app to throw errors and success messages. What I'm stuck with is that anytime the app throws a snack bar, the snack bar appears and disappears through the transparent navigation bar (i can see the snack bar move through the navigation bar). Is there any way to have the snack bar appear above the navigation bar? How can I position the snack bar above the system navigation bar?
You may want to look into SnackBarBehavior enum which allows one to change the position. If you are using a third party library then you may want to try putting the behavior into an extension method. Alternative ideas exist on this SO Question that may apply in your use case although not an exact duplicate.
The SnackbarBehavior enum states:
Defines where a SnackBar should appear within a Scaffold and how its location should be adjusted when the scaffold also includes a FloatingActionButton or a BottomNavigationBar.
Other ideas include using a position widget with a Stack widget to gain precise control. Add a MediaQuery or other fractional widgets to allow for multiple screen sizes.
I suggest you to use SnackBar Widget that developed by flutter team instead of Getx snackbar. It basically appears above of navigation bar here an basic example;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: ElevatedButton(
child: const Text('Show Snackbar'),
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Awesome Snackbar!'),
action: SnackBarAction(
label: 'Action',
onPressed: () {
// Code to execute.
},
),
),
);
},
),
),
bottomNavigationBar: 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,
),
);
}
static GetSnackBar SuccessSnackBar({String title = 'Success', String message}) {
Get.log("[$title] $message");
return GetSnackBar(
titleText: Text(title.tr, style: Get.textTheme.headline6.merge(TextStyle(color: Get.theme.primaryColor))),
messageText: Text(message, style: Get.textTheme.caption.merge(TextStyle(color: Get.theme.primaryColor))),
snackPosition: SnackPosition.BOTTOM,
margin: EdgeInsets.all(20),
backgroundColor: Colors.green,
icon: Icon(Icons.check_circle_outline, size: 32, color: Get.theme.primaryColor),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 18),
borderRadius: 8,
dismissDirection: DismissDirection.horizontal,
duration: Duration(seconds: 5),
);
}
Used like this in my app. Worked fine.
Get.snackbar(
"Bruh",
"Your quantity have to at least one",
colorText: Colors.black,
backgroundColor: Palette.yellowColor,
);
In my case, this is my return to show snackbar for error message, the snackbar appear on top below the appbar
In the getx snackbar there are a snackPosition: attribute
You can use that to display yours

How to define content and code for a button icon

I have just started programming with Flutter and Dart
And I wanted to know how to set the code and content for a tab or button
For example, I put a button icon in the bottom navigator and what code and method is needed so that after clicking on that button, a new page will open one by one and the operation will be performed.
Thanks.
For bottom navigation bar you can use like this:
`
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: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
backgroundColor: Colors.red,
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
backgroundColor: Colors.green,
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
backgroundColor: Colors.purple,
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
backgroundColor: Colors.pink,
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
`
You need to set onTap() for actions when you press the button and setState() to update the state of the widget.
All buttons (TextButton, ElevatedButton ect) will be having onTap() property, you can call a method inside onTap().
For more details visit this: https://flutter.dev/docs/development/ui/widgets/material#Buttons
This is a very specific use case and has a different solution to what you would usually do with buttons.
The documentation for the BottomNavigationBar() shows a few code examples. You can copy paste that and modify it to suit your need. What they basically do is add BottomNavigationBar() items and add an onChanged/onTap method which you would use to change the page.
For buttons in general, they would have an onPressed parameter where you can pass a function or an anonymous function (e.g. () {your code here}). Flutter provides you with a few default buttons such as ElevatedButton() and TextButton() which you can read more about here (https://api.flutter.dev/flutter/material/ElevatedButton-class.html) and here (https://api.flutter.dev/flutter/material/TextButton-class.html). They have parameters which allow you to tweak them. This is where you can run functions when they are pressed.
If you want to make a non-button widget clickable you can use a GestureDetector() which you can read more about here (https://api.flutter.dev/flutter/widgets/GestureDetector-class.html). It is also has an onTap similar to the buttons but also has much more options such as long, double, triple, etc. taps as well as gestures like swipes.
It all comes down to getting used to all those different widgets and you will get familiar with them through practice.

How to prevent iphone notch from overlapping content in bookmarked desktop app?

I'm using SafeArea to display a bottom navigation bar :
SafeArea(
child: ScaffoldMessenger(
child: Scaffold(
body: _tabs[index],
bottomNavigationBar: BottomNavigationBar(
selectedItemColor: Theme.of(context).primaryColor,
unselectedItemColor: Colors.grey,
showUnselectedLabels: true,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today), label: "Agenda"),
BottomNavigationBarItem(
icon: Icon(Icons.people), label: "Patients"),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet), label: "Comptes"),
BottomNavigationBarItem(
icon: Icon(Icons.settings), label: "Réglages"),
],
currentIndex: index,
onTap: (i) => context.read(navigationIndexProvider).index = i,
),
),
),
);
When bookmarked on iphone desktop, the safe area does not prevent the notch from overlapping the bottom navbar.
Here is the result :
How to properly prevent notch from overlapping the bottom bar ?
In SAFEAREA widget there is an argument -bottom
Set this bottom either true or false.
SafeArea(
bottom:true,
child:ScaffoldMessanger()
)
I don't remember the correct one, you can check both and let us know which one works for you.
I think since you're using bottomNavigationBar, the SafeArea should not be wrapped around Scaffold. It should be wrapped by Scaffold like this:
Scaffold(
body: SafeArea(child:
_tabs[index] ...
I think you should only wrap Scaffold with SafeArea when you're not using any kind of bottomNavigationBar

Title Only On Selected Bottom Navigation Bar

I am trying to create an effect on the Bottom Navigation Bar such as that of Google Drive. I want the title of the item only to be displayed, on the selected item, and the others to only display the icons.
Also, this bottom bar becomes somewhat transparent, so you can barely see what's under it. Is this possible to do in flutter? I know it is not possible on the main app bar, since there is an issue talking about it here
image for reference
Hide Title of Unselected BottomNavigationBarItem
You just need to set the show unselected labels property of the bottom navigation bar to false
showUnselectedLabels: false,
Transparent BottomNavigation bar
The Scaffold provides placeholders for both Appbar and BottomNavigation bars. This is how they are placed.
The problem here is that the body does not overlap the Appbar or the BottomNavigation bar, and thus even if you give transparent background it would appear to do nothing.
A workaround would be to put the Body, AppBar and BottomNavigationBar inside a stack and position the AppBar and BottomNavigationBar appropriately.
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Container(
color: Colors.green, // Content of body here
),
Positioned(
left: 0,
right: 0,
top: 0,
child: AppBar(
elevation: 0,
backgroundColor: Colors.indigo.withAlpha(80),
title: Text('Some Text'),
),
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: BottomNavigationBar(
elevation: 0,
showUnselectedLabels: false,
backgroundColor: Colors.red.withAlpha(80),
items: [
BottomNavigationBarItem(
title: Text('A'),
icon: Icon(Icons.add),
),
BottomNavigationBarItem(
title: Text('B'),
icon: Icon(Icons.remove),
),
],
),
),
],
),
);
}
}
U should use this code :
bottomNavigationBar: BottomNavigationBar(
//use both properties
type: BottomNavigationBarType.fixed,
showUnselectedLabels: true,
//-----------
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.icon1),
label:'item 1',
),
BottomNavigationBarItem(
icon: Icon(Icons.icon2),
label: 'item 2',
),
],
)

Changing the Bottom Navigation Bar when switching between screens in the body of a Scaffold

HomeScreen() function call the Home screen of App.
How I Can route/move to "Team", "Add", etcetera page without BottomNavigationBar and AppBar.
I want show another page and back button, with new Bottom Navigation Bar.
I have this on my Flutter Project:
class APPMain extends StatefulWidget {
#override
_APPMainState createState() => _APPMainState();
}
class _APPMainState extends State<APPMain> {
int _currentIndex = 0;
_onTapped(int index) {
setState(() {
_currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
List<Widget> screens = [
HomeScreen(),
Center(child: Text("Team")),
Center(child: Text("Add")),
Center(child: Text("Search")),
Center(child: Text("Settings")),
];
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xffffffff),
iconTheme: IconThemeData(color: Colors.grey),
title: Text("Test App", style: TextStyle(color: Colors.grey),),
actions: <Widget>[
IconButton(
icon: Icon(Icons.account_circle),
onPressed: (){},
),
],
),
body: Container(
color: Color(0xfff4f4f4),
child: Center(
child: screens[_currentIndex],
),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed,
fixedColor: Colors.red,
onTap: _onTapped,
items: [
BottomNavigationBarItem(
title: Text('Home'), icon: Icon(Icons.home)),
BottomNavigationBarItem(
title: Text('Team'), icon: Icon(Icons.group)),
BottomNavigationBarItem(
title: Text('Add'), icon: Icon(Icons.add)),
BottomNavigationBarItem(
title: Text('Search'), icon: Icon(Icons.search)),
BottomNavigationBarItem(
title: Text('Settings'), icon: Icon(Icons.settings)),
]),
);
}
}
Thank you so much for help.
This is almost certainly a duplicate but I wasn't able to find a question asking something similar with a quick search so I'll answer anyways.
The answer is actually quite simple, but requires understanding a bit more about how to write flutter applications - you should be using a Navigator or the navigator built right into MaterialApp or WidgetApp rather than making your own navigation. The simplest way is to use MaterialApp's routes property and pass in a map with each of your pages. Then when you want to switch pages, you simply use Navigator.pushNamed(context, <name>) from wherever you want to switch the page (i.e. a button).
The part that can be slightly confusing when you come from other frameworks is that rather than having one Scaffold and switching the body of it, the entire page should switch and each page should have a Scaffold.
Here's an example in the documentation showing how to navigate between pages.
For the record, although it's a bad idea you could make it work with your original code as well - all you'd have to do is build a different BottomNavigationBar with different options depending on what _currentIndex is set to. But I don't recommend that. With what I've suggested you also get animations between pages, back button functionality, you can hook up analytics to track page usage, and a bunch more things that flutter provides as part of navigation.