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

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.

Related

How can I change Icon colors when it's selected in flutter?

I'm new to flutter. I want to Icon colors be black except when they clicked. Either the color doesn't change when I click, or I can't change the color of the clicked one. I saw this ternary solution but I don't know why it isn't working.
class _RootAppState extends State<RootApp> {
int _selectedIndex = 0;
int? currentIndex;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text('Index 0: Home', style: optionStyle,),
...
];
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, size: 25),
label: 'Home',
),...
],
currentIndex: _selectedIndex,
selectedItemColor: _selectedIndex == currentIndex ? Colors.black :Colors.amber[800],
onTap: _onItemTapped,
),
);
}
im pretty new to this too, looking from my app i just added this in
try adding this in
type: BottomNavigationBarType.fixed,
Try using CupertinoTabScaffold. In state changes, the color of the tab you are in will light up momentarily. You can also change this color with Theme.

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));

how to show the drawer icon on bottom right in 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();

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.

Set color on active item in a BottomNavigationBarType.fixed

I have a fixed BottomNavigationBar with 4 items as described below.
How can I set the color of the selected item?
I've tried with: fixedColor and selectedItemColor but it would't work.
BottomNavigationBar(
type: BottomNavigationBarType.fixed,
fixedColor: Colors.blue,
//selectedItemColor: Colors.blue,
currentIndex: snapshot.data.index,
onTap: _bottomNavBarBloc.pickItem,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.access_time,
color: Colors.black,
),
),
BottomNavigationBarItem(...),
BottomNavigationBarItem(...),
BottomNavigationBarItem(...),
]);
You can provide a different icon for Active and Normal Bottom Navigation Item.
BottomNavigationBarItem _getNavigationItem(IconData icon, String title) {
return BottomNavigationBarItem(
backgroundColor: Colors.white,
activeIcon: Icon(
icon,
color: Colors.teal,
),
icon: Icon(icon, color: Colors.grey),
title: Text(title),
);
}
There are two types available. fixed or shifting. If we add fixed type , the buttons inside bottom navigation does not show any effect when use click a particular button. It just keep fixed to the bottom navigation. If we add shifting , it will show some kind of cool animation when we click a particular button.
Check this out here
A workaround perhaps would be something like this though:
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
home: new MyHomePage(),
));
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int currentIndex = 0;
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("StackoverFlow"),
),
body: Container(),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: currentIndex,
onTap: (index) {
setState(() {
currentIndex = index;
});
},
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.access_time,
color: currentIndex == 0? Colors.blue:Colors.black,
),
title: Container(),
),
BottomNavigationBarItem(
icon: Icon(
Icons.access_time,
color: currentIndex == 1? Colors.blue:Colors.black,
),
title: Container(),
),
]),
);
}
}