I have a Bottom Navigation Bar using FlutterIcons and I would like to use either onTap() or onPressed() on them to switch between screens in the app. How can I achieve this?
Here's my code snippet:
bottomNavigationBar: CurvedNavigationBar(
backgroundColor: Constants.scaffoldBackgroundColor,
buttonBackgroundColor: Constants.primaryColor,
items: [
Icon(
FlutterIcons.ios_home_ion,
size: 20.0,
color: activeIndex == 0 ? Colors.white : Color(0xFF000B70),
),
Icon(
FlutterIcons.file_pdf_box_mco,
size: 20.0,
color: activeIndex == 1 ? Colors.white : Color(0xFF000B70),
),
Icon(
FlutterIcons.qrcode_scan_mco,
size: 20.0,
color: activeIndex == 2 ? Colors.white : Color(0xFF000B70),
),
Icon(
FlutterIcons.notifications_active_mdi,
size: 20.0,
color: activeIndex == 3 ? Colors.white : Color(0xFF000B70),
),
Icon(
FlutterIcons.setting_ant,
size: 20.0,
color: activeIndex == 4 ? Colors.white : Color(0xFF000B70),
),
],
onTap: (index) {
setState(() {
activeIndex = index;
});
},
),
CurvedNavigationBar doesn't provide onPressed, use onTap as you've define.
bottomNavigationBar: CurvedNavigationBar(
items: [
],
onTap: (index) {
setState(() {
activeIndex = index;
});
},
body:yourWidgetList[activeIndex]
),
More about curved_navigation_bar
Demo widget
class AGG extends StatefulWidget {
const AGG({Key? key}) : super(key: key);
#override
State<AGG> createState() => _AGGState();
}
class _AGGState extends State<AGG> {
List<Widget> pages = [
Text("Page 1"),
Text("Page 2"),
Text("Page 3"),
];
int activeIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: CurvedNavigationBar(
backgroundColor: Colors.blueAccent,
items: <Widget>[
Icon(Icons.add, size: 30),
Icon(Icons.list, size: 30),
Icon(Icons.compare_arrows, size: 30),
],
onTap: (index) {
setState(() {
activeIndex = index;
});
},
),
body: pages.elementAt(activeIndex),
);
}
}
You can explore more about BottomNavigationBar
The difference between onTap() and onPressed is the moment of execution. As you can imagine onPressed() fires as soon as user touches the item without necessarily removing the finger from tap area.
onTap() fires only after full tap has been detected meaning- item has been touched and touch was quickly removed. Quickly meaning faster than gets detected by onLongPress().
To use different touch types you can wrap every navigation item individually in GestureDetector or Inkwell or wrap the whole bar in one of those and pass a parameter to detect which item has been pressed.
Think of it as difference between tapping your arm and pressing on your arm.
Use whichever makes more sense in your scenario (I'd suggest onTap()). Hope that helps.
Related
I want to navigate to a page when I click navbar items. I tried this using a gesture detector widget. but it's not working here. and for one icon I want to add a snack bar to display coming soon. how can I do this. appreciate your help on this.
navigate to a page
display snack bar with the text "coming soon"
class BottomNavigation extends StatefulWidget {
const BottomNavigation({ Key? key }) : super(key: key);
#override
State<BottomNavigation> createState() => _BottomNavigationState();
}
class _BottomNavigationState extends State<BottomNavigation> {
int _selectedindex = 0;
void _navigatePages(int index) {
setState(() {
_selectedindex = index;
});
}
final List<Widget> _Pages = [const Dashboard() ,const WelcomeScreen()];
#override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
body: _Pages[_selectedindex],
bottomNavigationBar: Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(24),
topLeft: Radius.circular(24),
),
// color: Colors.transparent,
),
child: BottomNavigationBar(
backgroundColor: Colors.grey.withOpacity(0.6),
currentIndex: _selectedindex,
onTap: _navigatePages,
type: BottomNavigationBarType.fixed,
items: const [
BottomNavigationBarItem(
icon: ImageIcon(
AssetImage("assets/images/wallet.png"),
color: Colors.black,
size: 32,
),
label: "",
),
BottomNavigationBarItem(
icon: ImageIcon(
AssetImage("assets/images/store.png"),
color: Colors.black,
size: 32,
),
label: "",
),
BottomNavigationBarItem(
icon: ImageIcon(
AssetImage("assets/images/coin.png"),
color: Colors.black,
size: 32,
),
label: "",
)
]),
),
);
}
}
I didn't understand if you can navigate to a screen or not, but I copied your code as is and I can navigate, anyway I leave you this little change that you can do if you can't go to another page:
BottomNavigationBar(
backgroundColor: Colors.grey.withOpacity(0.6),
currentIndex: _selectedindex,
onTap: (int i) => _navigatePages(i), // here
type: BottomNavigationBarType.fixed,
items: const [
[...]
Now, to show a Snackbar, in your function _navigatePages you only make a small validation that if the index is the last one (that is the 2), show the snackbar, first hide one if it exists... if not do the setState.
void _navigatePages(int index) {
if (index == 2) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text("coming soon")));
} else {
setState(() {
_selectedindex = index;
});
}
}
Your full code is ok, just you need to add a Snackbar for your needed index. Suppose, you have three Bottom Navigation Bar & you will show your snackbar for the last Bottom Navigation icon, which means the index will be 2. [this index will be changed based on your decision]
Your _navigatePages() function will be changed like as below code :
void _navigatePages(int index) {
if(index == 2){
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text("coming soon")));
}else{
ScaffoldMessenger.of(context).hideCurrentSnackBar();
setState(() {
_selectedindex = index;
});
}
}
N.B: Please change the function only, others all code is ok.
I use a classic NavigationRail, inside a Row() divided in two, to change the view. But I would also like to change the view by clicking on items displayed in the view.
For example, at the beginning ShowTables() is visible, and when I click on buttons built by ShowTables(), I want to replace ShowTables() by an other widget. This new widget could have the possibility to return to ShowTables(), keeping the value of my Map Tables (or at least my app state data if not possible). How can I do ?
class NavBarTest extends StatefulWidget {
final Metadata? data;
const NavBarTest({Key? key, required this.data}) : super(key: key);
#override
State<NavBarTest> createState() => _NavBarTestState();
}
class _NavBarTestState extends State<NavBarTest> {
Map tables = {};
int _selectedIndex = 0;
#override
void initState() {
/*
here I init tables...
*/
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child:
Row(
children: <Widget>[
NavigationRail(
groupAlignment: -1.0,
selectedIndex: _selectedIndex,
leading:
Column(children: [
SizedBox(
height: MediaQuery.of(context).size.height/3,
),
SizedBox(
width: 50,
height: 50,
child: Image.asset("assets/logo.png"),
),
],),
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: NavigationRailLabelType.none,
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.spoke_rounded,color: icon),
selectedIcon: Icon(Icons.spoke_rounded,color: Colors.yellow),
label: Text('First'),
),
NavigationRailDestination(
icon: Icon(Icons.show_chart_sharp,color: icon),
selectedIcon: Icon(Icons.show_chart_sharp,color: Colors.yellow),
label: Text('Second'),
),
NavigationRailDestination(
icon: Icon(Icons.info_sharp,color: icon),
selectedIcon: Icon(Icons.info_outline,color: Colors.yellow),
label: Text('Third'),
),
],
),
// This is the main content.
Expanded(
child: buildPage(_selectedIndex)
)
],
)
)
);
}
Widget buildPage(index){
switch (index) {
case 0:
return ShowTables(tables: tables);
case 1:
return const Details();
case 2:
return Links(tables: tables);
default:
return ShowTables(tables: tables);
}
}
}
I am New to Flutter actually I am not a coder but I am trying to build an app that can do basic things like the sign-in page, sign up, user data showing to the screen, and also I can see each other profile from the app I Stuck in the Bottom Navigation bar here which I never thought that it would be hard to get through.
instead of giving up, I decided to google around and come up with different results (some of them are hard to understand and confusing).
I am trying to build a navigation bar that routs to different pages with minimum memory usage (efficient code)
I am so confused and I don't know now what to do! please help another coder(if someone fixes this I am going to consider myself a coder, don't think too much)
#override
Widget build(BuildContext context) {
PageController _pageController = PageController();
final List<Widget> _tabs = [FeedPage(), ListingPage(), SettingPage()];
int _selectedIndex = 0;
void _onPageChanged(int index) {
setState(() { //Is something wrong with my setState?
_selectedIndex = index;
});
}
void _onItemTapped(int _selectedIndex) {
_pageController.jumpToPage(_selectedIndex);
}
return Scaffold(
body: PageView(
controller: _pageController,
children: _tabs,
onPageChanged: _onPageChanged, //Check it out
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex, //I use this
onTap: _onItemTapped,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
),
title: Text("Home"),
),
BottomNavigationBarItem(
icon: Icon(
Icons.list,
),
title: Text("List"),
),
BottomNavigationBarItem(
icon: Icon(
Icons.person,
),
title: Text("Profile"),
),
],
),
);
}
}
//is this the code bugged? or something wrong in my flutter IED or something I am confused
try this code below, insert this code just before the scaffold perntesis, also dont forget to insert the packacge.
bottomNavigationBar: CurvedNavigationBar(
color: Colors.black26,
backgroundColor: Color(0xFFFFC5C5),
buttonBackgroundColor: Colors.greenAccent,
height: 50.0,
animationCurve: Curves.bounceInOut,
items: <Widget>[
Icon(Icons.translate, size: 20, color: Colors.black),
Icon(Icons.translate, size: 20, color: Colors.black),
Icon(Icons.list, size: 20, color: Colors.black),
Icon(Icons.account_balance, size: 20,
color: Colors.black),
// Icon(Icons.camera, size: 20, color: Colors.black),
],
index: 2,
animationDuration: Duration(milliseconds: 400),
onTap: (index) {
debugPrint("Curent index is $index");
}
)
Okay I see you havent mentioned color in your icons so as page changes let us apply the same logic to avoid confusion.
So let us have a list of colors declared below final list of _tabs
List<Color> selectedColor = [Colors.grey[900],Colors.grey[900],Colors.grey[900]];
Now we have assign these to our icons as
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
color: selectedColor[0], //Add here
),
title: Text("Home"),
),
BottomNavigationBarItem(
icon: Icon(
Icons.list,
color: selectedColor[1], //Add here
),
title: Text("List"),
),
BottomNavigationBarItem(
icon: Icon(
Icons.person,
color: selectedColor[2], //Add here
),
title: Text("Profile"),
),
],
Now due to this mentioned in the list all have a grey colour
void updateColor(int num){
//here I am again declaring it because when I select the other color the list should //always remain same for the effect you want
selectedColor = [Colors.grey[900],Colors.grey[900],Colors.grey[900]];
setState(() {
switch(num){
case 1 : selectedColor[0] = Colors.Red;
break;
case 2 : selectedColor[1] = Colors.Red;
break;
case 3 : selectedColor[2] = Colors.Red;
break;
}
});
}
Now what we will do is call this on your onChanged function or you can also mention it in onTap but I dont understand why you used both at the same time
I will use
void _onItemTapped(int _selectedIndex) {
setState(() { //Is something wrong with my setState?
_selectedIndex = index;
updateColor(_selectedIndex);
});
_pageController.jumpToPage(_selectedIndex);
}
You can simply change the colors in the bottom navigation bar as follows.
Change the main color of
color: Colors.orange,
Change the Background color
backgroundColor: Colors.white,
Change the Icon background-color
buttonBackgroundColor: Colors.orangeAccent,
Change the Icon Size
Icon(Icons.person, size: 30),
The sample code as follows
bottomNavigationBar: CurvedNavigationBar(
color: Colors.orange,
backgroundColor: Colors.white,
buttonBackgroundColor: Colors.orangeAccent,
items: <Widget>[
Icon(Icons.person, size: 30),
Icon(Icons.close, size: 30),
Icon(Icons.settings, size: 30),
],
onTap: (index) {
//Handle button tap
},
),
Hope this will fix your problem.
I've made an app that's got a row of three buttons that when pressed are supposed to:
1) turn bold
2) change the output on the page
I've solved step 1 by doing this:
The page's class has an instance variable:
List<bool> _boldButtons = [false, true, false];
Each button's TextStyle has the fontWeight property:
fontWeight: _boldButtons[0] ? FontWeight.bold : FontWeight.normal),
And its onPresed:
onPressed: () {
setState(() {
_boldButtons = [true, false, false];
});
This feels hacky, but does the trick. If anyone has a better way of doing this I'd be more then happy to hear!
To solve problem 2) I'm thinking of doing something like this:
Make three methods (notifications(), yourRecipes(), favorites() ) that return a Container.
Have an instance variable in the page's class that is of that type:
Container wallOfText;
In each button's onPressed we set the wallOfText variable to be equal to that button's function, something like this:
onPressed: () {
wallOfText = boldButtons[0] ? wallOfText : notifications();
// ternary operator to check if we've already selected the button we're pressing, and therefore don't need to redefine what to display
setState(() {
_boldButtons = [true, false, false];
});
Then we display the wallOfText variable in the Scaffold.
This also feels really hacky, but might work. Is there a more general way of doing this?
I have changed little bit in your code, like i have take single variable which hold the selected tab value and update it on tab selection, have a look on below code for it.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class HomeScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _HomeScreen();
}
}
class _HomeScreen extends State<HomeScreen> {
var selectedTab = 1;
var selectedText="First Tab";
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: Container(
child: Column(
children: <Widget>[
Container(
color: Colors.deepOrange,
child:Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FlatButton(
onPressed: () {
setState(() {
selectedTab=1;
selectedText="First Tab";
});
},
child: Text(
"Notifications",
style: TextStyle(
fontWeight:
selectedTab == 1 ? FontWeight.bold : FontWeight.normal),
),
),
FlatButton(
onPressed: () {
setState(() {
selectedTab=2;
selectedText="Second Tab";
});
},
child: Text(
"Your recipe",
style: TextStyle(
fontWeight:
selectedTab == 2 ? FontWeight.bold : FontWeight.normal),
),
),
FlatButton(
onPressed: () {
setState(() {
selectedTab=3;
selectedText="Third Tab";
});
},
child: Text(
"Favorites",
style: TextStyle(
fontWeight:
selectedTab == 3 ? FontWeight.bold : FontWeight.normal),
),
),
],
) ,
)
,
Container(
width: double.infinity,
height: MediaQuery.of(context).size.height*0.6,
child: Align(
alignment: Alignment.center,
child: Text(selectedText),
),
)
],
),
),
);
}
}
And please check the output of it
I have created a List in Flutter using Sliver (Sliver Structure below):
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
//leading: Icon(Icons.arrow_back),
expandedHeight: 150.0,
pinned: true,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
final item = taskList[index];
return Card()
The Card has a Dismissible Widget encapsulated within which creates a ListTile. The Dismissible works fine and I can swipe to dismiss individual cells in the list.
The issue I am having is related to an IconButton in my ListTile. My aim is that whenever I tap the IconButton it should toggle an Icon Flag on or off for the individual cell, but what happens is that all of the Icon Buttons in the List are toggled. From investigating the Dismissible Widget code I can understand that I need to uniquely identify each cell for this to work, I've tried using a Key to make the cells unique but that hasn't worked. Is anybody able to steer me in the right direction? The code for the IconButton is below, I also attempted to add a key to the ListTile but that didn't work so I removed it.
IconButton(
key: Key(item),
icon: Icon(Icons.flag),
color: (isPriority) ? Colors.red : Colors.grey,
onPressed: _toggleFlag,
)
My toggleFlag code is below, I already have a setState in there, it toggles the flag but the issue is that it toggles all flags in the list when i want to toggle the flag of the cell that it belongs to:
void _toggleFlag() {
setState(() {
if (isPriority) {
isPriority = false;
} else {
isPriority = true;
}
});
}
Create your card like this
return new Users(example: taskList[index]);
then craete widget for card
class Users extends StatefulWidget
{
final String example;
const Users ({Key key, this.example}) : super(key: key);
#override
UserWidgets createState() => UserWidgets();
}
class UserWidgets extends State<Users>
{
#override
Widget build(BuildContext context)
{
return new Container(
child: Card(
child:new IconButton(
icon: Icon(Icons.flag),
color: (isPriority) ? Colors.red : Colors.grey,
onPressed: ()
{
setState(() {
if (isPriority) {
isPriority = false;
} else {
isPriority = true;
}
});
}
,
),
);
}
I have been able to simplify my code to capture all of it and show where the icon button fits in (the icon button is right at the bottom). I'm still getting the issue that if I tap on an icon flag all of the icon flags are then toggled on rather than the specific one that I tapped.
class HomePage extends StatefulWidget {
_HomePageDemoState createState() => _HomePageDemoState();
}
class _HomePageDemoState extends State<HomePage> {
List<String> taskList = [
'The Enchanted Nightingale',
'The Wizard of Oz',
'The BFG'
];
bool isPriority = false;
void _toggleFlag() {
setState(() {
if (isPriority) {
isPriority = false;
} else {
isPriority = true;
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
final item = taskList[index];
return Card(
elevation: 8.0,
child: ListTile(
contentPadding: EdgeInsets.all(0.0),
leading: Container(
color: (isPriority) ? Colors.red : Colors.grey,
//padding: EdgeInsets.only(right: 12.0),
padding: EdgeInsets.all(20.0),
child: Text(
'01',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
title: Text('$item'), //Text('The Enchanted Nightingale'),
subtitle:
Text('Music by Julie Gable. Lyrics by Sidney Stein.'),
trailing: IconButton(
key: Key(item),
icon: Icon(Icons.flag),
color: (isPriority) ? Colors.red : Colors.grey,
onPressed: _toggleFlag,
),
),
);
},
childCount: taskList.length,
),
),
],
),
);
}
}