how to show the drawer icon on bottom right in flutter? - flutter

I need to show the the total of 5 icons (4 bottom navigation icon + 1 menu drawer icon) in the bottom of the page. I am using BottomNavigationBarItem to show the four bottom navigation icons. In that i need to add the menu drawer icon. I can find answers for only bottom right and left. Kindly help to resolve this
class HomeScreen extends StatefulWidget{
final int indexvalue;
HomeScreen({Key key, #required this.indexvalue}) : super(key: key);
#override
State createState() {
return HomeScreenState();
}
}
class HomeScreenState extends State<HomeScreen> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
int _selectedPage = 0;
final _pageOptions = [
Screen1(),
WebView1(),
Home(),
Leader(),
];
#override
Widget build(BuildContext context){
Size size = MediaQuery.of(context).size;
var val = widget.indexvalue;
print(widget.indexvalue);
return MaterialApp(
title: 'Home',
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(title: Text('Home'),),
body: _pageOptions[_selectedPage],
endDrawer: build_1(),
bottomNavigationBar: new Theme(
data: Theme.of(context).copyWith(
// sets the background color of the `BottomNavigationBar`
canvasColor: Colors.green,
// sets the active color of the `BottomNavigationBar` if `Brightness` is light
primaryColor: Colors.red,
textTheme: Theme
.of(context)
.textTheme
.copyWith(caption: new TextStyle(color: Colors.yellow))), // sets the inactive color of the `BottomNavigationBar`
child: new BottomNavigationBar(
showSelectedLabels: false, // <-- HERE
showUnselectedLabels: false,
currentIndex: _selectedPage,
onTap: (int index) {
setState(() {
_selectedPage = index;
});
},
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Home')),
BottomNavigationBarItem(icon: Icon(Icons.photo_library), title: Text('photo_library')),
BottomNavigationBarItem(icon: Icon(Icons.book), title: Text('book')),
BottomNavigationBarItem(icon: Icon(Icons.notifications), title: Text('download')),
],
),
),
)
);
}
}
build_1(){
return SizedBox(
//width: size.width,
child: Drawer(
child: new ListView(
children: <Widget>[
new DrawerHeader(
child: new Text("Drawer Header"),
decoration: new BoxDecoration(
color: Colors.blue,
),
),
new Text("Item 1"),
new Text("Item 2"),
new Text("Item 3"),
new Text("Item 4"),
new Text("Item 5"),
new Text("Item 6"),
],
),
),
);
}

You can add another item in your bottomNavigationBar
BottomNavigationBarItem(icon: Icon(Icons.menu), title: Text('Menu'))
and check the index in onTap method and call _scaffoldKey.currentState.openDrawer(); to open the drawer
onTap: () {
int menuIndex = 4;//if you want it to be the last(bottom right)
if (index == menuIndex) {
_scaffoldKey.currentState.openDrawer();
}
else {
setState(() {
_selectedPage = index;
});
}
}
}
if you want to just add an icon everywhere in your screen to open your drawer just call
_scaffoldKey.currentState.openDrawer(); in onTap method
For exampe:
IconButton(
icon: Icon(Icons.menu),
color: Colors.white,
onPressed: () {
_scaffoldKey.currentState.openDrawer();
},)

If you are using in your Scaffold:
drawer: Drawer() use _scaffoldKey.currentState.openDrawer();
endDrawer: Drawer() use _scaffoldKey.currentState.openEndDrawer();

Related

How to disable a button in the BottomNavigationBar flutter [duplicate]

I have BottomNavigationBar with 5 items and also FloatingActionButton that should change 3rd item 'Photo'.
So I need if user press on central BottomNavigationBarItem 'Photo' it didn't affect switching to this tab.
How can I disable clicking on specific BottomNavigationBarItem?
And here is my code:
import 'package:flutter/material.dart';
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => new _MainPageState();
}
class PageInfoData {
final String title;
final IconData iconData;
const PageInfoData(this.title, this.iconData);
}
class _MainPageState extends State<MainPage> {
int _selectedIndex = 0;
static const List<PageInfoData> pageInfo = [
PageInfoData('History', Icons.swap_horiz),
PageInfoData('Download', Icons.file_download),
PageInfoData('Photo ', null),
PageInfoData('Upload', Icons.file_upload),
PageInfoData('Settings', Icons.settings)
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text("Menu"),
actions: <Widget>[IconButton(icon: Icon(Icons.search, color: Colors.white,),)],
),
body: Center(child: Text('Index$_selectedIndex: ${pageInfo[_selectedIndex].title}')),
backgroundColor: Colors.white,
bottomNavigationBar: BottomNavigationBar(
items: new List<BottomNavigationBarItem>.generate(pageInfo.length, (int index) {
PageInfoData curPageInfo = pageInfo[index];
return BottomNavigationBarItem(icon: Icon(curPageInfo.iconData, size: 30.0), title: Text(curPageInfo.title, style: TextStyle(fontSize: 9.0),));
}),
type: BottomNavigationBarType.fixed,
unselectedItemColor: const Color(0xff797979),
fixedColor: Theme.of(context).primaryColor,
backgroundColor: const Color(0xffe2e2e2),
currentIndex: _selectedIndex,
showUnselectedLabels: true,
onTap: _onItemTapped,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: FloatingActionButton(
backgroundColor: Color(0xffa2a5a4),
child: Icon(Icons.photo_camera, size: 40.0,),
onPressed: null),
);
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
}
UPDATE:
Problem almost solved (thank you #ibhavikmakwana) by changing _onItemTapped function
void _onItemTapped(int index) {
if (index != 2) {
setState(() {
_selectedIndex = index;
});
}
}
But it solved not completely.
When I tap photo label it still show me a tap splash effect.
Can I disable a tap splash effect?
I had the same issue as yours. In my case, I just only want to apply it on bottomNavigationBar, because I have splash effect on another widget.
I fixed it using this code below:
bottomNavigationBar: Theme(
data: ThemeData(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
child: BottomNavigationBar(),
),
You can do something like below:
Your bottomNavigationBar
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
),
],
onTap: navigationTapped,
currentIndex: _page,
),
You can add the conditional check whether the page index match with the current index than don't do anything and return from that point.
Like page == index
Where, index is position of the BottomNavigationBarItem
void navigationTapped(int page) {
if (page == 1) {
return;
} else {
setState(() {
_selectedIndex = page;
});
}
}
To extend the correct answers given here, the correct way to disable splash effect, you should copy the existing app ThemeData and override only the splashColor and highlighColor properties.
Otherwise the other app ThemeData properties will be lost.
Wrap your widget with Theme widget and instead:
Theme(
data: ThemeData(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
child: YourWidget(),
);
Use:
Theme(
data: Theme.of(context).copyWith(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
child: YourWidget(),
);
Maybe you can try this to disable splash effect:
Change the splashColor or splashFactory in ThemeData to Colors.transparent.
Reference:
How to disable default Widget splash effect in Flutter?
To disable the splash effect in BottomNavigationBar, wrap it in a Theme widget, and override the values of splashColor and highlightColor with Colors.transparent.

how can I achieve a bottom navigation bar with these features?

There are five navigation items in total and the widths are 154,153,154,153,154. I know it's kind of strange but the UI design is like this. As for this I guess I cannot use any Widget about navigator in the flutter lib.
Each item contains an icon and a text as usual but the distance between the two should be set exactly. I don't know if it can be set in flutter widget bottomNavigatorBar.
Commonly, the color of the icon, text and the background will change when selected.
What I have done: I created a widget and add it to the bottom of every pages. As you can imagine, when jumping to a new page, the navigation bar will re-render. That is not the same as we use in our mobile phones.
I have found some articles and blogs, but still can't solve my problem. Is there any reference?
You can use the below code and redirect this page into main.dart and can use test and icon also.
class nav extends StatefulWidget {
#override
_navState createState() => _navState();
}
class _navState extends State<nav> {
int tabIndex = 0;
List<Widget> listScreens;
#override
void initState() {
ScreenUtil.init(width: 375, height: 812);
super.initState();
listScreens = [
Home(),
Treatments(),
Request(),
Appointments(),
Menu(),
];
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: listScreens[tabIndex],
bottomNavigationBar: new Theme(
data: Theme.of(context).copyWith(
canvasColor: Color(0xFF320151),
primaryColor: Color(0xFF320151)),
child: BottomNavigationBar(
backgroundColor: Color(0xFF38095c),
selectedItemColor: Color(0xFFe34fd1),
unselectedItemColor: Color(0xFF510382),
currentIndex: tabIndex,
onTap: (int index) {
setState(() {
tabIndex = index;
});
},
items: [
BottomNavigationBarItem(
title: Text(""),
icon: Container(
width: 154, child: Center(child: Icon(AntDesign.home))),
),
BottomNavigationBarItem(
title: Text(""),
icon: Container(
width: 153,
child: Center(
child: Icon(MaterialCommunityIcons.medical_bag))),
),
BottomNavigationBarItem(
title: Text(""),
icon: Container(
width: 154,
child: Center(child: Icon(Fontisto.share_a))),
),
BottomNavigationBarItem(
title: Text(""),
icon: Container(
width: 153,
child: Center(child: Icon(AntDesign.calendar))),
),
BottomNavigationBarItem(
title: Text(""),
icon: Container(
width: 154,
child: Center(child: Icon(Ionicons.ios_person))),
),
]),
)),
);
}
}

Flutter: "Multiple GlobalKeys in the Widget tree" while Navigation

I'm facing an issue of "Multiple GlobalKeys in the Widget tree" while Navigation.
I have a BottomNavigationBar & a Drawer defined in the Scaffold of a Base Screen and in the body parameter of Scaffold I have multiple screens which I'm accessing with BottomNavigationBar. The thing is, I'm accessing the Drawer of the Base Screen from one of the multiple screens by using a GlobalKey, and everything's working fine but when I Navigate to the Base Screen from Another Screen then I get the above-mentioned error.
I have tried a solution of not using a static keyword while defining the key and it solves the error of navigation but then I can't access the Drawer because then I get another error of "method 'openDrawer' was called on null".
This is a separate class where I have defined the Key:
class AppKeys {
final GlobalKey<ScaffoldState> homeKey = GlobalKey<ScaffoldState>();
}
This is the Base Screen:
class Base extends StatefulWidget {
#override
_BaseState createState() => _BaseState();
}
class _BaseState extends State<Base> {
int selectedScreen = 0;
final screens = List<Widget>.unmodifiable([Home(), Cart(), Orders(), Help()]);
AppKeys appKeys = AppKeys();
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: MyDrawer(),
key: appKeys.homeKey,
body: screens[selectedScreen],
bottomNavigationBar: SizedBox(
height: 80,
child: BottomNavigationBar(
onTap: (val) {
setState(() {
selectedScreen = val;
});
},
currentIndex: selectedScreen,
selectedItemColor: AppColor.primary,
elevation: 20.0,
unselectedItemColor: Colors.grey,
showUnselectedLabels: true,
type: BottomNavigationBarType.fixed,
iconSize: 25,
selectedFontSize: 15,
unselectedFontSize: 15,
items: [
BottomNavigationBarItem(
icon: Icon(AnanasIcons.home), title: Text("Home")),
BottomNavigationBarItem(
icon: Icon(AnanasIcons.cart), title: Text("Cart")),
BottomNavigationBarItem(
icon: Icon(AnanasIcons.orders), title: Text("My Orders")),
BottomNavigationBarItem(
icon: Icon(AnanasIcons.help), title: Text("Help")),
],
),
),
);
}
}
This is the Home Screen from where I'm accessing the Drawer:
class Home extends StatelessWidget {
final AppKeys appKeys = AppKeys();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(
AnanasIcons.menu,
color: Colors.black,
),
onPressed: () {
appKeys.homeKey.currentState.openDrawer();
}),
backgroundColor: Theme.of(context).canvasColor,
title: Text("Hi"),
actions: [
IconButton(
icon: Icon(
Icons.person,
color: Colors.black,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Profile(),
));
})
],
),
body: Container(),
);
}
}
I've found the answer! Instead of pushing the route with the key, we need to remove all the routes from the stack till the screen where we have to go.
Here's the code for that:
Navigator.of(context).popUntil(ModalRoute.withName(Base.routeName));

Hide the bottom navigation bar when clicking on one bottom navigation bar item (and loading related page) - Flutter

I have a bottom navigation bar defined separately in a file, containing 5 items, and loading 5 pages (which doesn't have defined a bottom navigation bar). It should be present on 4 of the loaded pages but should disappear on the 5th page (CHAT). All the solutions I found online refers to hiding the bar while scrolling up or down, I think I'm quite close to the expected result but I didn't sort it out yet... The code for that "controller" that generates the B-N-Bar is below, a screenshot with the bottom as well. Thank you.
class BottomNavigationBarController extends StatefulWidget {
#override
_BottomNavigationBarControllerState createState() =>
_BottomNavigationBarControllerState();
}
class _BottomNavigationBarControllerState
extends State<BottomNavigationBarController> {
final List<Widget> pages = [
MyHome(
key: PageStorageKey('Page1'),
),
MyStats(
key: PageStorageKey('Page2'),
),
MyCategories(
key: PageStorageKey('Page3'),
),
MyPeopleList(
key: PageStorageKey('Page4'),
),
MyChat(
key: PageStorageKey('Page5'),
),
];
final PageStorageBucket bucket = PageStorageBucket();
int _selectedIndex = 0;
Widget _bottomNavigationBar(int selectedIndex) => BottomNavigationBar(
onTap: (int index) => setState(() => _selectedIndex = index),
currentIndex: selectedIndex,
type: BottomNavigationBarType.fixed,
//
iconSize: 24,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text(
'HOME',
),
),
BottomNavigationBarItem(
icon: Icon(Icons.insert_chart),
title: Text(
'STATS',
),
),
BottomNavigationBarItem(
icon: Icon(Icons.view_list),
title: Text(
'INVENTORY',
),
),
BottomNavigationBarItem(
icon: Icon(Icons.group),
title: Text(
'PEOPLE',
),
),
BottomNavigationBarItem(
icon: Icon(Icons.forum),
title: Text(
'CHAT',
),
),
],
);
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: _bottomNavigationBar(_selectedIndex),
body: PageStorage(
child: pages[_selectedIndex],
bucket: bucket,
),
);
}
}
I did it with an IF/Else in the bottom:
#override
Widget build(BuildContext context) {
if (_selectedIndex < 4) {
return Scaffold(
bottomNavigationBar: _bottomNavigationBar(_selectedIndex),
body: PageStorage(
child: pages[_selectedIndex],
bucket: bucket,
),
);
} else {
return Scaffold(
body: PageStorage(
child: pages[_selectedIndex],
bucket: bucket,
),
);
}
}

How can I have the BottomNavigationBar respond to navigation to a new page via AlertDialog?

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.