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.
Related
For my flutter project, I am using google_nav_bar. Every time I click on a button in the nav_bar I want to navigate to another page. I want to do this without making the nav bar my home page and loading other pages to the nav bar.
import 'package:flutter/material.dart';
import 'package:google_nav_bar/google_nav_bar.dart';
import 'package:space_flight_recorder/view/home.dart';
import '../view/about.dart';
import '../view/upcoming.dart';
import '../view/previous.dart';
class Nav_bar extends StatefulWidget {
const Nav_bar({super.key});
#override
State<Nav_bar> createState() => _Nav_barState();
}
class _Nav_barState extends State<Nav_bar> {
bool status = false;
int index = 0;
#override
Widget build(BuildContext context) {
return
// body: _pages[_index],
SingleChildScrollView(
// scrollDirection: Axis.horizontal,
child: GNav(
// onTabChange: (index) {
// setState(() {
// _index = index;
// });
// },
curve: Curves.easeInOut,
backgroundColor: Colors.black,
color: Colors.white,
activeColor: Colors.blue,
tabBackgroundColor: Colors.transparent,
gap: 3,
hoverColor: Colors.grey,
iconSize: 30,
tabs: [
GButton(
text: 'HOME',
icon: Icons.home,
onPressed:(){
index=1;
},
),
GButton(
text: 'PREVIOUS',
icon: Icons.restart_alt,
onPressed:(){
index=2;
},
),
GButton(
text: 'UPCOMING',
icon: Icons.rocket_launch,
onPressed:(){
index=3;
},
),
GButton(
text: 'ABOUT',
icon: Icons.info,
onPressed:(){
index=4;
},
),
],
onTabChange: pagechange(),
),
);
}
pagechange() {
if (index==1)
{
Navigator.pushNamed(context, 'home');
}
if (index==2)
{
Navigator.pushNamed(context, 'previous');
}
if (index==3)
{
Navigator.pushNamed(context, 'upcoming');
}
if (index==4)
{
Navigator.pushNamed(context, 'info');
}
}
}
I have also set the bottom navbar in all of the pages that I navigate to as follows
bottomNavigationBar: Nav_bar(),
In this code, the page is not changing, and when I write the Navigator.pushedName function in the onPressed function itself, then page is changed but the animation at the bottom is absent, it just gets stuck at home.
All I want is to change the page as we click the button and change the animation of the nav bar with it without making the bottom nav bar class as my page which in turns load all the other pages using setState() etc.
I am using this dependency
google_nav_bar: ^5.0.6
You've forgot to call setState like
GButton(
text: 'HOME',
icon: Icons.home,
onPressed:(){
setState((){
index=1;
});
},
),
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.
I have a MainPage with bottomnavigation bar with bottomnavigation items. I want to call APIs of bottomnavigation item pages whenever i tap on it i.e I want to reload page everytime I vist the page.
But in my case its not reloading everytime but at once when mainpage called all api of bottomnavigation items page APIs are called attime.
MainPage
class MainPage extends StatefulWidget{
#override
_MainPageState createState() => new _MainPageState();
}
class _MainPageState extends State<MainPage>{
ListQueue<int> _navigationQueue = ListQueue();
int _selectedIndex = 0;
int counter = Constant.CART_COUNT;
List<GlobalKey<NavigatorState>> _navigatorKeys = [
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>()
];
Future<void> secureScreen() async {
await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
}
#override
void initState() {
// TODO: implement initState
super.initState();
secureScreen();
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (_navigationQueue.isEmpty) return true;
setState(() {
_navigationQueue.removeLast();
int position = _navigationQueue.isEmpty ? 0 : _navigationQueue.last;
_selectedIndex = position;
});
return false;
},
child: Scaffold(
backgroundColor: Colors.white,
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _selectedIndex,
selectedItemColor: Colors.blueAccent,
showSelectedLabels: true,
showUnselectedLabels: false,
items: [
BottomNavigationBarItem(
icon: Icon(
FontAwesome.home,
color: Colors.grey,
),
label: 'Home',
activeIcon: Icon(
FontAwesome.home,
color: Colors.blueAccent,
),
),
BottomNavigationBarItem(
icon: Icon(
FontAwesome.product_hunt,
color: Colors.grey,
),
label: 'Products',
activeIcon: Icon(
FontAwesome.product_hunt,
color: Colors.blueAccent,
),
),
BottomNavigationBarItem(
icon: Icon(
FontAwesome.users,
color: Colors.grey,
),
label: 'Customers',
activeIcon: Icon(
FontAwesome.users,
color: Colors.blueAccent,
),
),
BottomNavigationBarItem(
icon: Icon(
FontAwesome.search_plus,
color: Colors.grey,
),
label: 'Order Details',
activeIcon: Icon(
FontAwesome.users,
color: Colors.blueAccent,
),
),
],
onTap: (index) {
if(_selectedIndex == _selectedIndex){
_navigationQueue.removeWhere((element) => element == index);
_navigationQueue.addLast(index);
setState(() {
this._selectedIndex = index;
});
}
},
),
body: Stack(
children: [
_buildOffstageNavigator(0),
_buildOffstageNavigator(1),
_buildOffstageNavigator(2),
_buildOffstageNavigator(3)
],
),
),
);
}
Map<String, WidgetBuilder> _routeBuilders(BuildContext context, int index) {
return {
'/': (context) {
return [
HomePage(),
ProductSearchPage(),
CustomerPage(),
OrdersPage()
].elementAt(index);
},
};
}
Widget _buildOffstageNavigator(int index) {
var routeBuilders = _routeBuilders(context, index);
return Offstage(
offstage: _selectedIndex != index,
child: Navigator(
key: _navigatorKeys[index],
onGenerateRoute: (routeSettings) {
return MaterialPageRoute(
builder: (context) => routeBuilders[routeSettings.name]!(context),
);
},
),
);
}
}
You have used an offstage widget which will just remove the ui from the stage. It wont reload when the index is changed. You have to create a list
List screens = [
HomePage(),
ProductSearchPage(),
CustomerPage(),
OrdersPage()
],
//Then in body use
body: screens[index]
You can set the api call in on Tap because all the pages will be initialized at a time that's why you are facing this issue.
Just check the condition on Tap for a currently selected index and write down the API call there.
I have 4 pages in bottom navigation bar. I am facing a problem related to route that i want to route to a specific page in bottom navigation bar from another page?
e.g I am going to login page and post successful login I want to route user to accountdetails(AccountSetting) but if I am selecting account setting then in that page bottom navigation bar is not showing and if I am routing to bottom nav bar here I am unable to select index of my choice. How can I select index of my choice because I don't want to make new page having bottom nav bar?
class BottomNavBar extends StatefulWidget {
static String routeName = "/bottombar";
#override
_BottomNavBarState createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
CartCountController cartCountController = CartCountController();
DoublePressBackBotton doublePressBackBotton = DoublePressBackBotton();
int _selectedIndex = 0;
#override
void initState() {
Future.delayed(Duration(milliseconds: 1000)).then((value) {
cartCountController.cartItemCount();
});
super.initState();
}
#override
void dispose() {
Future.delayed(Duration(milliseconds: 1000)).then((value) {
cartCountController.cartItemCount();
});
super.dispose();
}
List _widgetOptions = [
HomeScreen(),
CategoryList(),
InviteFriend(),
AccountSetting(),
];
void _onItemTapped(
int index,
) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return
// drawer: SideDrawer(),
body: WillPopScope(
child: _widgetOptions.elementAt(_selectedIndex),
onWillPop: () {
return doublePressBackBotton.doubleBack();
},
),
bottomNavigationBar: BottomNavigationBar(
// backgroundColor: Color(0xff202020),
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
backgroundColor: kPrimaryColor,
icon: Icon(
Icons.home_outlined,
color: Colors.white,
),
label: 'Home',
),
BottomNavigationBarItem(
backgroundColor: kPrimaryColor,
icon: Icon(
Icons.category,
color: Colors.white,
),
label: 'Category',
),
BottomNavigationBarItem(
backgroundColor: kPrimaryColor,
icon: ImageIcon(
AssetImage(AppImages.phonecall),
color: Colors.white,
),
label: 'Invite',
),
BottomNavigationBarItem(
backgroundColor: kPrimaryColor,
icon: Icon(
Icons.person_outlined,
color: Colors.white,
),
label: 'Account',
),
],
// fixedColor: Colors.black,
currentIndex: _selectedIndex,
// selectedItemColor: Color(0xffF9C000),
onTap: _onItemTapped,
showUnselectedLabels: true,
selectedItemColor: kPrimaryLightColor,
// unselectedItemColor: Color(0xff737373),
unselectedLabelStyle: GoogleFonts.lato(color: Colors.white),
selectedLabelStyle: GoogleFonts.lato(color: Colors.white),
),
);
// );
}
}
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,
),
),
],
),
);
}
}