Related
I have flutter app and in my app I have to show bottom navigatiobar for every page
I am confuse that should I can navigate with with bottom navigation bar or I have to add bottom navigation bar for every page
If I use Navigation I have to use scaffold as parent of all widget so is it any way to navigate with scaffold.
Here is my code:-
class WorkerHomeScreen extends StatelessWidget {
WorkerHomeScreen({Key? key}) : super(key: key);
int _selectedPageIndex = 0;
List<Map<String, dynamic>> get _pages {
return [
{"page": SignInScreen(), "name": "PROPERTY", "action": null},
{
"page": ChoseRoleScreen(),
"name": "CHAT",
"action": ["Search"]
},
{"page": LandingPage(), "name": "VIDEO", "action": null},
{"page": EmployerSignUpScreen(), "name": "PROFILE", "action": null}
];
}
void _selectPage(int index) {
_selectedPageIndex = index;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
),
body: _pages[_selectedPageIndex]["page"],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: _selectPage,
currentIndex: _selectedPageIndex,
items: [
BottomNavigationBarItem(
icon: Icon(workerNavigationLists[0].icon),
label: "Property",
activeIcon: Icon(workerNavigationLists[0].icon),
),
BottomNavigationBarItem(
icon: Icon(workerNavigationLists[1].icon),
label: "Chat",
activeIcon: Icon(workerNavigationLists[0].icon),
),
BottomNavigationBarItem(
icon: Icon(workerNavigationLists[0].icon),
label: "Video",
),
BottomNavigationBarItem(
icon: Icon(workerNavigationLists[0].icon),
label: "Profile",
activeIcon: Icon(workerNavigationLists[0].icon),
),
],
),
);
}
}
Here is my screen:-
class SignInMobile extends StatelessWidget {
SignInMobile({Key? key}) : super(key: key);
final SignInController signInController = Get.find();
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: RaisedButton(
onPressed: () {
/// I want to navigate to other page but I want navigation bar in other page also
},
child: Text("TAP TO NAVIGATE"),
),
),
);
}
}
So from the Discussion I have Create an example
Check this link below for demo:
https://github.com/sagaracharya24/bottomApp.git
So in order to make this implementation you have have a knowledge of following things
OnGenerate Route mechanism.
GlobalKeys and NavigatorState.
Know how Offstage widget works under the hood.
What you will get from the Example:
Each Page maintains the stack of pages as per BottomBarItem.
If you are deep inside the nested pages and click in the same item, it will remove all the pages and com back to the main page.
I have also add the sample Gif To show you the app is working.
Let me know the if it works for you thanks.
You can use persistent_bottom_nav_bar to achieve your expectation. Do as follows:
late PersistentTabController _controller;
#override
void initState() {
super.initState();
_controller = PersistentTabController(initialIndex: 0);
}
List<PersistentBottomNavBarItem> _navBarsItems() {
return [
PersistentBottomNavBarItem(
icon: Image.asset('assets/logowhite.png', height: 30, width: 30),
inactiveIcon:
Image.asset('assets/logowhite.png', height: 30, width: 30),
title: "Vesvusa",
textStyle: const TextStyle(color: Colors.white),
activeColorPrimary: MyTheme.grey,
activeColorSecondary: Colors.white,
contentPadding: 5,
inactiveColorPrimary: Colors.white,
inactiveColorSecondary: Colors.white,
routeAndNavigatorSettings: RouteAndNavigatorSettings(
initialRoute: '/dashboard',
routes: {
'/newsevents': (context) => NewsListScreen(
menuScreenContext: context,
hideMainAppBar: hideMainAppBar,
itemCount: null),
'/blogdetails': (context) => BlogDetails(
menuScreenContext: context,
hideMainAppBar: hideMainAppBar,
),
'/videoslist': (context) => VideosList(menuScreenContext: context),
'/bookings': (context) => Bookings(menuScreenContext: context),
'/lookstheme': (context) => LooksTheme(menuScreenContext: context),
'/catalog': (context) => Catalog(menuScreenContext: context),
'/productdetails': (context) =>
ProductDetails(menuScreenContext: context),
},
),
),
PersistentBottomNavBarItem(
icon: Image.asset(
'assets/search.png',
height: 25,
width: 25,
color: Colors.white,
),
inactiveIcon: Image.asset(
'assets/search.png',
height: 25,
width: 25,
color: Colors.white,
),
title: ("Search"),
activeColorPrimary: MyTheme.grey,
activeColorSecondary: Colors.white,
contentPadding: 5,
inactiveColorPrimary: Colors.white,
inactiveColorSecondary: Colors.white,
routeAndNavigatorSettings: const RouteAndNavigatorSettings(
initialRoute: '/search',
routes: {
// '/first': (context) => MainScreen2(),
// '/second': (context) => MainScreen3(),
},
),
),
PersistentBottomNavBarItem(
icon: Image.asset(
'assets/favourite.png',
height: 25,
width: 25,
color: Colors.white,
),
inactiveIcon: Image.asset(
'assets/favourite.png',
height: 25,
width: 25,
color: Colors.white,
),
title: ("Favorite"),
activeColorPrimary: MyTheme.grey,
activeColorSecondary: Colors.white,
contentPadding: 5,
inactiveColorPrimary: Colors.white,
inactiveColorSecondary: Colors.white,
textStyle: const TextStyle(color: Colors.white),
routeAndNavigatorSettings: const RouteAndNavigatorSettings(
initialRoute: '/favorite',
routes: {
// '/first': (context) => MainScreen2(),
// '/second': (context) => MainScreen3(),
},
),
// onPressed: (context) {
// pushDynamicScreen(context,
// screen: SampleModalScreen(), withNavBar: true);
// }
),
PersistentBottomNavBarItem(
icon: Image.asset(
'assets/cart.png',
height: 25,
width: 25,
color: Colors.white,
),
inactiveIcon: Image.asset(
'assets/cart.png',
height: 25,
width: 25,
color: Colors.white,
),
title: ("Cart"),
activeColorPrimary: MyTheme.grey,
activeColorSecondary: Colors.white,
contentPadding: 5,
inactiveColorPrimary: Colors.white,
inactiveColorSecondary: Colors.white,
textStyle: const TextStyle(color: Colors.white),
routeAndNavigatorSettings: const RouteAndNavigatorSettings(
initialRoute: '/cart',
routes: {
// '/first': (context) => MainScreen2(),
// '/second': (context) => MainScreen3(),
},
),
),
PersistentBottomNavBarItem(
icon: Image.asset(
'assets/profile.png',
height: 25,
width: 25,
color: Colors.white,
),
inactiveIcon: Image.asset(
'assets/profile.png',
height: 25,
width: 25,
color: Colors.white,
),
title: ("Profile"),
activeColorPrimary: MyTheme.grey,
activeColorSecondary: Colors.white,
contentPadding: 5,
inactiveColorPrimary: Colors.white,
inactiveColorSecondary: Colors.white,
textStyle: const TextStyle(color: Colors.white),
routeAndNavigatorSettings: RouteAndNavigatorSettings(
initialRoute: '/profile',
routes: {
'/orders': (context) => MyOrders(
menuScreenContext: context,
),
'/loginsecurity': (context) => LoginSecurity(
menuScreenContext: context,
),
'/payment': (context) => Payment(
menuScreenContext: context,
),
'/message': (context) => Messages(
menuScreenContext: context,
),
'/devices': (context) => Devices(
menuScreenContext: context,
),
'/devices': (context) => Devices(
menuScreenContext: context,
),
'/inboxdetails': (context) => InboxDetails(
menuScreenContext: context,
),
'/loyalty': (context) => Loyalty(menuScreenContext: context),
},
),
),
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: MyTheme.themeColor,
appBar: AppBar(
elevation: 0,
iconTheme: IconThemeData(
color: MyTheme.grey,
),
centerTitle: true,
backgroundColor: MyTheme.themeColor,
title: Image.asset("assets/titles.png", height: 60, width: 100),
actions: [
Builder(
builder: (context) {
return InkWell(
onTap: () {
Scaffold.of(context).openEndDrawer();
},
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 20, 0),
child: Icon(Icons.notifications_none_outlined,
color: MyTheme.grey),
));
},
)
],
),
drawer: MyDrawer(),
endDrawer: const NotificationDrawer(),
body: PersistentTabView(
context,
controller: _controller,
screens: _buildScreens(),
items: _navBarsItems(),
confineInSafeArea: true,
backgroundColor: MyTheme.themeColor,
handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: true,
stateManagement: true,
hideNavigationBarWhenKeyboardShows: true,
margin: const EdgeInsets.all(0.0),
popActionScreens: PopActionScreensType.once,
bottomScreenMargin: 0.0,
onWillPop: (context) async {
await showDialog(
context: context!,
useSafeArea: false,
builder: (context) => CommonAlert());
return false;
},
selectedTabScreenContext: (context) {
context = context;
},
hideNavigationBar: _hideNavBar,
popAllScreensOnTapOfSelectedTab: true,
itemAnimationProperties: const ItemAnimationProperties(
duration: Duration(milliseconds: 200),
curve: Curves.ease,
),
screenTransitionAnimation: const ScreenTransitionAnimation(
animateTabTransition: true,
curve: Curves.ease,
duration: Duration(milliseconds: 200),
),
navBarStyle:
NavBarStyle.style7, // Choose the nav bar style with this property
),
);
}
You can navigate to other page doing this
pushNewScreen(context,
screen: Loyalty(
menuScreenContext: context,
),pageTransitionAnimation:PageTransitionAnimation.scale);
},
You don't need to add BottomNavigationBar in all pages if you define it in your HomePage (Your first page) only.
if you dont want to use any packages in order to maintain the appsize or reduce it, please use the inbuilt flutter bottom navigation
import 'package:flutter/material.dart';
class Mynavigation extends StatefulWidget {
const Mynavigation({Key key}) : super(key: key);
#override
State<Mynavigation> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<Mynavigation> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
List<Widget> _widgetOptions = <Widget>[
Home(),Business(),School(), Settings()
];
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(
type: BottomNavigationBarType.fixed,
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 do notice this line having
Home(),Business(),School(), Settings(),
those should be individual pages where you want to navigate to.SO PLEASE change them to point to the pages you want to use.
and then one more thing just replace Mynavigation with WorkerHomeScreen and you are good to go,
if your using flutter sdk >2.12.0
please use on this line
static const List<Widget> _widgetOptions = <Widget>[
else if your sdk is below 2.12.0 then use
List<Widget> _widgetOptions = <Widget>[
incase of any question, I will be waiting
Good luck bro
You can simply add BottomNevigatioBar using scaffold property and add multiple Page to the List. Hope you got your solution
import 'package:flutter/material.dart';
import 'package:traveling/helpers/AppColors.dart';
import 'package:traveling/screens/Employee/home/Home.dart';
import 'package:traveling/screens/Employee/profile/Profile.dart';
import 'package:traveling/screens/Employee/setting/Setting.dart';
class EmployeeBottomNavBar extends StatefulWidget {
const EmployeeBottomNavBar({Key? key}) : super(key: key);
#override
_EmployeeBottomNavBarState createState() => _EmployeeBottomNavBarState();
}
class _EmployeeBottomNavBarState extends State<EmployeeBottomNavBar> {
int pageIndex = 0;
bool visible = true;
List<Widget> pageList = <Widget>[EmployeeHome(), Profile(leadingIcon: false,), Setting()];
#override
Widget build(BuildContext context) {
return Scaffold(
body: pageList[pageIndex],
bottomNavigationBar: BottomNavigationBar(
fixedColor: Colors.redAccent[400],
currentIndex: pageIndex,
onTap: (value) {
setState(() {
pageIndex = value;
});
},
// type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
activeIcon: Container(
height: 40,
width: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color(0xff2161c0),
),
child: Icon(
Icons.home,
color: AppColors.white,
),
),
icon: Icon(
Icons.home,
color: Color(0xff2161c0),
),
label: ""),
BottomNavigationBarItem(
activeIcon: Container(
height: 40,
width: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color(0xff2161c0),
),
child: Icon(
Icons.person,
color: AppColors.white,
),
),
icon: Icon(
Icons.person,
color: AppColors.baseLightBlueColor,
),
label: ""),
BottomNavigationBarItem(
activeIcon: Container(
height: 40,
width: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColors.baseLightBlueColor,
),
child: Icon(
Icons.settings,
color: AppColors.white,
),
),
icon: Icon(
Icons.settings,
color: AppColors.baseLightBlueColor,
),
label: ""),
]
)
);
}
}
I am making a app in which I am using package snake bottom navigation and advanced drawer. Both are configured fine in a file but I'm having issue when when I want to use the function on a new page to open and close the drawer. I am unable to import it to my HomePage file where I am making the home page of the app. This code
void _handleMenuButtonPressed() {
_advancedDrawerController.showDrawer();
}
is the one creating issue in the drawer screen onpressed and on valuelistener.
Here is my Dashboard code which contains bottom nav and drawer:
class Dashboard extends StatefulWidget {
const Dashboard({Key? key}) : super(key: key);
#override
State<Dashboard> createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
final _advancedDrawerController = AdvancedDrawerController();
int _selectedIndex = 0;
final PageController _pageController = PageController();
ShapeBorder? bottomBarShape = const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
);
SnakeBarBehaviour snakeBarStyle = SnakeBarBehaviour.floating;
EdgeInsets padding = const EdgeInsets.all(12);
SnakeShape snakeShape = SnakeShape.circle;
bool showSelectedLabels = true;
bool showUnselectedLabels = true;
Color selectedColor = Colors.black;
Gradient selectedGradient =
const LinearGradient(colors: [Colors.red, Colors.amber]);
Color unselectedColor = Colors.black;
Gradient unselectedGradient =
const LinearGradient(colors: [Colors.black, Colors.black]);
Color? containerColor;
List<Color> containerColors = [
const Color(0xFFFDE1D7),
const Color(0xFFE4EDF5),
const Color(0xFFE7EEED),
const Color(0xFFF4E4CE),
];
#override
Widget build(BuildContext context) {
return AdvancedDrawer(
backdropColor: kblue,
controller: _advancedDrawerController,
animationCurve: Curves.easeInOut,
animationDuration: const Duration(milliseconds: 300),
animateChildDecoration: true,
rtlOpening: false,
disabledGestures: false,
childDecoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(16)),
),
drawer: SafeArea(
child: Container(
color: kblue,
child: ListTileTheme(
textColor: Colors.white,
iconColor: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 128.0,
height: 128.0,
margin: const EdgeInsets.only(
top: 24.0,
bottom: 64.0,
),
clipBehavior: Clip.antiAlias,
decoration: const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: Image.asset(
'assets/logo.png',
scale: 3,
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.home),
title: const Text(
'Home',
style: TextStyle(),
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.account_circle_rounded),
title: const Text(
'Profile',
style: TextStyle(),
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.notifications),
title: const Text(
'Notifications',
style: TextStyle(),
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.bug_report),
title: const Text(
'Report a bug',
style: TextStyle(),
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.logout),
title: const Text(
'Logout',
style: TextStyle(),
),
),
const Spacer(),
DefaultTextStyle(
style: const TextStyle(
fontSize: 12,
),
child: GestureDetector(
onTap: () {},
child: Container(
margin: const EdgeInsets.symmetric(
vertical: 16.0,
),
child: const Text(
'Terms of Service | Privacy Policy',
style: TextStyle(),
),
),
),
),
],
),
),
),
),
child: Scaffold(
extendBodyBehindAppBar: true,
resizeToAvoidBottomInset: true,
extendBody: true,
bottomNavigationBar: SnakeNavigationBar.color(
behaviour: snakeBarStyle,
snakeShape: snakeShape,
shape: bottomBarShape,
padding: padding,
snakeViewColor: selectedColor,
selectedItemColor: snakeShape == SnakeShape.indicator
? selectedColor
: Colors.orange,
unselectedItemColor: Colors.black,
showUnselectedLabels: showUnselectedLabels,
showSelectedLabels: showSelectedLabels,
currentIndex: _selectedIndex,
onTap: (index) => setState(() => _selectedIndex = index),
items: const [
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'tickets'),
BottomNavigationBarItem(
icon: Icon(Icons.person), label: 'calendar'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'home'),
BottomNavigationBarItem(
icon: Icon(Icons.person), label: 'microphone'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'search'),
],
selectedLabelStyle: const TextStyle(fontSize: 14),
unselectedLabelStyle: const TextStyle(fontSize: 10),
),
body: PageView(
controller: _pageController,
children: const <Widget>[
HomePage(),
HomePage(),
HomePage(),
HomePage(),
HomePage(),
],
onPageChanged: (page) {
setState(() {
_selectedIndex = page;
});
},
),
),
);
}
void _handleMenuButtonPressed() {
_advancedDrawerController.showDrawer();
}
}
Code to HomePage which contains the button to open and close the drawer and thats where the issue is:
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: SafeArea(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
onPressed: _handleMenuButtonPressed,
icon: ValueListenableBuilder<AdvancedDrawerValue>(
valueListenable: _advancedDrawerController,
builder: (_, value, __) {
return AnimatedSwitcher(
duration: const Duration(milliseconds: 250),
child: Icon(
value.visible ? Icons.clear : Icons.menu,
key: ValueKey<bool>(value.visible),
),
);
},
),
),
],
),
),
],
),
),
),
);
}
}
You can do it this way. There's no need to separate the files when you can do in one
class Dashboard extends StatefulWidget {
const Dashboard({Key? key}) : super(key: key);
#override
State<Dashboard> createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
final _advancedDrawerController = AdvancedDrawerController();
int _selectedIndex = 0;
final PageController _pageController = PageController();
ShapeBorder? bottomBarShape = const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
);
SnakeBarBehaviour snakeBarStyle = SnakeBarBehaviour.floating;
EdgeInsets padding = const EdgeInsets.only(top: 0);
SnakeShape snakeShape = SnakeShape.circle;
final double elevation = 4;
bool showSelectedLabels = true;
bool showUnselectedLabels = true;
Color selectedColor = Colors.white;
Gradient selectedGradient =
const LinearGradient(colors: [Colors.blue, Colors.pink]);
Color unselectedColor = Colors.black;
Gradient unselectedGradient =
const LinearGradient(colors: [Colors.black, Colors.black]);
Color? containerColor;
List<Color> containerColors = [
const Color(0xFFFDE1D7),
const Color(0xFFE4EDF5),
const Color(0xFFE7EEED),
const Color(0xFFF4E4CE),
];
#override
Widget build(BuildContext context) {
return AdvancedDrawer(
backdropColor: kblue,
controller: _advancedDrawerController,
animationCurve: Curves.easeInOut,
animationDuration: const Duration(milliseconds: 300),
animateChildDecoration: true,
rtlOpening: false,
disabledGestures: false,
childDecoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(16)),
),
drawer: SafeArea(
child: Container(
color: kblue,
child: ListTileTheme(
textColor: Colors.white,
iconColor: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 128.0,
height: 128.0,
margin: const EdgeInsets.only(
top: 24.0,
bottom: 64.0,
),
clipBehavior: Clip.antiAlias,
decoration: const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: Image.asset(
'assets/logo.png',
scale: 3,
),
),
ListTile(
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const Dashboard()));
},
leading: const Icon(Icons.home),
title: const Text(
'Home',
style: TextStyle(),
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.account_circle_rounded),
title: const Text(
'Profile',
style: TextStyle(),
),
),
ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const NotificationsScreen()));
},
leading: const Icon(Icons.notifications),
title: const Text(
'Notifications',
style: TextStyle(),
),
),
ListTile(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => ReportBug()));
},
leading: const Icon(Icons.bug_report),
title: const Text(
'Report a bug',
style: TextStyle(),
),
),
ListTile(
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const LoginPage()));
},
leading: const Icon(Icons.logout),
title: const Text(
'Logout',
style: TextStyle(),
),
),
const Spacer(),
DefaultTextStyle(
style: const TextStyle(
fontSize: 12,
),
child: GestureDetector(
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const TermsandPolicies()));
},
child: Container(
margin: const EdgeInsets.symmetric(
vertical: 16.0,
),
child: const Text(
'Terms of Service | Privacy Policy',
style: TextStyle(),
),
),
),
),
],
),
),
),
),
child: Scaffold(
appBar: AppBar(
backgroundColor: const Color(0xFFFAFAFA),
elevation: 0,
centerTitle: true,
title: const Text(
'Dhrop',
style: TextStyle(
letterSpacing: 1,
color: Colors.black,
),
),
automaticallyImplyLeading: false,
leading: IconButton(
onPressed: _handleMenuButtonPressed,
icon: ValueListenableBuilder<AdvancedDrawerValue>(
valueListenable: _advancedDrawerController,
builder: (_, value, __) {
return AnimatedSwitcher(
duration: const Duration(milliseconds: 250),
child: Icon(
value.visible ? Icons.clear : Icons.menu,
color: Colors.black,
key: ValueKey<bool>(value.visible),
),
);
},
),
),
),
extendBodyBehindAppBar: true,
resizeToAvoidBottomInset: true,
extendBody: true,
bottomNavigationBar: SnakeNavigationBar.color(
backgroundColor: kblue,
behaviour: snakeBarStyle,
snakeShape: snakeShape,
shape: bottomBarShape,
padding: const EdgeInsets.only(
bottom: 15,
left: 10,
right: 10,
),
snakeViewColor: selectedColor,
selectedItemColor:
snakeShape == SnakeShape.indicator ? selectedColor : kblue,
unselectedItemColor: Colors.black,
showUnselectedLabels: showUnselectedLabels,
showSelectedLabels: showSelectedLabels,
currentIndex: _selectedIndex,
onTap: (index) => setState(() => _selectedIndex = index),
items: [
BottomNavigationBarItem(
icon: IconButton(
icon: const Icon(
Icons.home,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const HomePage()));
},
),
// label: 'Home',
),
BottomNavigationBarItem(
icon: IconButton(
icon: const Icon(
Icons.search,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SearchPage()));
},
),
// label: 'Search',
),
BottomNavigationBarItem(
icon: IconButton(
icon: const Icon(
Icons.message,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const MessagesPage()));
},
),
// label: 'Messages',
),
BottomNavigationBarItem(
icon: IconButton(
icon: const Icon(
Icons.luggage,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DropPage()));
},
),
// label: 'Drop',
),
],
selectedLabelStyle: const TextStyle(fontSize: 12),
unselectedLabelStyle: const TextStyle(fontSize: 14),
),
body: PageView(
controller: _pageController,
children: const <Widget>[
HomePage(),
SearchPage(),
MessagesPage(),
DropPage()
],
onPageChanged: (page) {
setState(() {
_selectedIndex = page;
});
},
),
),
);
}
void _handleMenuButtonPressed() {
_advancedDrawerController.showDrawer();
}
}
how can I make bottom bar to look same like in image, top corners to be rounded and to icons have the space same like in image.
here is code of bottomMenu bar how is right now.. so basically to have rounded corner and to icon have padding from left and right. but if I add whole BottomNavigationBar in padding then it not move just icons.. hope that somebody can help me to fix this..
Scaffold(
body: _handlePages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
items: <BottomNavigationBarItem>[
_currentIndex == 0
? BottomNavigationBarItem(
icon: Image.asset(
"assets/images/cam.png",
height: 25,
color: appColorBlue,
),
label: "",
)
: BottomNavigationBarItem(
icon: Image.asset(
"assets/images/cam.png",
height: 25,
color: appColorGrey,
),
label: "",
),
_currentIndex == 1
? BottomNavigationBarItem(
icon: Image.asset(
"assets/images/call_blue.png",
height: 27,
color: appColorBlue,
),
label: "",
)
: BottomNavigationBarItem(
icon: Image.asset(
"assets/images/call_blue.png",
height: 27,
color: appColorGrey,
),
label: "",
),
_currentIndex == 2
? BottomNavigationBarItem(
icon: Image.asset(
"assets/images/chat.png",
height: 27,
color: appColorBlue,
),
label: "",
)
: BottomNavigationBarItem(
icon: Image.asset(
"assets/images/chat.png",
height: 27,
color: appColorGrey,
),
label: "",
),
_currentIndex == 3
? BottomNavigationBarItem(
icon: Container(
height: 30,
width: 30,
child: new Stack(
children: <Widget>[
globalImage.length > 0
? CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(globalImage),
)
: Container(
height: 30,
width: 30,
decoration: BoxDecoration(
color: Colors.grey[400],
shape: BoxShape.circle),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Image.asset(
"assets/images/user.png",
height: 10,
color: Colors.white,
),
)),
],
),
),
// Image.asset(
// "assets/images/settings.png",
// height: 25,
// color: appColorBlue,
// ),
label: "",
)
: BottomNavigationBarItem(
icon: Container(
height: 30,
width: 30,
child: new Stack(
children: <Widget>[
globalImage.length > 0
? CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(globalImage),
)
: Container(
height: 30,
width: 30,
decoration: BoxDecoration(
color: Colors.grey[400],
shape: BoxShape.circle),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Image.asset(
"assets/images/user.png",
height: 10,
color: Colors.white,
),
)),
],
),
),
// Image.asset(
// "assets/images/settings.png",
// height: 25,
// color: appColorGrey,
// ),
label: "",
),
],
),
),
You can create your own bottom nav bar so that you can design it freely.
Sample...
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: List.generate(
100,
(index) => ListTile(
title: Text('TEST $index'),
),
),
),
bottomNavigationBar: const RoundedBottomNavBar(
onTap: print,
children: const <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.camera_alt)),
BottomNavigationBarItem(icon: Icon(Icons.phone)),
BottomNavigationBarItem(icon: Icon(Icons.send)),
BottomNavigationBarItem(icon: Icon(Icons.circle)),
],
childrenPadding: const EdgeInsets.symmetric(horizontal: 10),
),
);
}
}
class RoundedBottomNavBar extends StatefulWidget {
const RoundedBottomNavBar({
required this.onTap,
required this.children,
this.background = Colors.white,
this.topCornerRadius = 20,
this.childrenPadding = const EdgeInsets.all(0),
});
final ValueChanged<int> onTap;
final List<BottomNavigationBarItem> children;
final Color background;
final double topCornerRadius;
final EdgeInsetsGeometry childrenPadding;
#override
_RoundedBottomNavBarState createState() => _RoundedBottomNavBarState();
}
class _RoundedBottomNavBarState extends State<RoundedBottomNavBar> {
late Radius _topCornerRadius;
int _selectedIndex = 0;
#override
void initState() {
super.initState();
_topCornerRadius = Radius.circular(widget.topCornerRadius);
}
#override
Widget build(BuildContext context) {
int tmpCount = 0;
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
color: widget.background,
borderRadius: BorderRadius.only(
topLeft: _topCornerRadius,
topRight: _topCornerRadius,
),
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: widget.children.map((BottomNavigationBarItem item) {
final int index = tmpCount++;
return GestureDetector(
onTap: () {
setState(() => _selectedIndex = index);
widget.onTap(index);
},
child: Opacity(
opacity: _selectedIndex == index ? 1 : 0.3,
child: Padding(
padding: widget.childrenPadding,
child: item.icon,
),
),
);
}).toList(),
),
),
);
}
}
a solution can be adding your custom bottomNvigationBar, playing with the colors and the shadow, also de radius, something like this:
this is the body
Scaffold(
bottomNavigationBar: bottom(),
appBar: AppBar(
title: Center(child: Text("test")),
),
body: Container(),
);
and here is the bottom widget:
Widget bottom() {
return Container(
height: 60, //you can do it with mediaQuery
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 5.0,
spreadRadius: 2.0,
),
],
color: Colors.blue,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25),
topRight: Radius.circular(25),
)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
GestureDetector(
onTap: () {
print("hello, i press ");
},
child: Icon(
Icons.camera_alt,
size: 35,
),
),
GestureDetector(
onTap: () {
print("hello, i press ");
},
child: Icon(
Icons.phone,
size: 35,
),
),
GestureDetector(
onTap: () {
print("hello, i press ");
},
child: Icon(
Icons.near_me,
size: 35,
)),
],
));
}
here a screenshot of the result:
I have the following Flutter bottom navigation bar
And I would like to add a top-line or boarder for active items like so
Is that even possible, my code is straight forward.
#override
Widget build(BuildContext context) {
return Scaffold(
body: _tabs[_tabIndex],
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.white,
selectedLabelStyle: TextStyle(fontSize: 14),
selectedItemColor: Theme.of(context).accentColor,
unselectedLabelStyle: TextStyle(fontSize: 14.0),
unselectedItemColor: Color(0xff546481),
type: BottomNavigationBarType.fixed,
showSelectedLabels: true,
showUnselectedLabels: true,
currentIndex: _tabIndex,
onTap: (int index) {
setState(() {
_tabIndex = index;
});
},
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home_outlined),
label: 'HOME',
),
BottomNavigationBarItem(
icon: Icon(Icons.history_outlined),
label: 'HISTORY',
),
BottomNavigationBarItem(
icon: Icon(Icons.person_outline),
label: 'PROFILE',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings_outlined),
label: 'SETTINGS',
),
],
),
);
}
}
there are some packages can achieve this effect:
titled_navigation_bar
bottomNavigationBar: TitledBottomNavigationBar(
currentIndex: 2, // Use this to update the Bar giving a position
onTap: (index){
print("Selected Index: $index");
},
items: [
TitledNavigationBarItem(title: Text('Home'), icon: Icons.home),
TitledNavigationBarItem(title: Text('Search'), icon: Icons.search),
TitledNavigationBarItem(title: Text('Bag'), icon: Icons.card_travel),
TitledNavigationBarItem(title: Text('Orders'), icon: Icons.shopping_cart),
TitledNavigationBarItem(title: Text('Profile'), icon: Icons.person_outline),
]
)
bottom_indicator_bar
class _HomePageState extends State<HomePage> {
final List<BottomIndicatorNavigationBarItem> items = [
BottomIndicatorNavigationBarItem(icon: Icons.home),
BottomIndicatorNavigationBarItem(icon: Icons.search),
BottomIndicatorNavigationBarItem(icon: Icons.settings),
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Indicator Bottom Bar"),
backgroundColor: Colors.teal,
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
],
),
),
bottomNavigationBar: BottomIndicatorBar(
onTap: (index) => {},
items: items,
activeColor: Colors.teal,
inactiveColor: Colors.grey,
indicatorColor: Colors.teal,
),
);
}
}
You can use a TabBar instead of a BottomNavigationBar using a custom decoration:
class TopIndicator extends Decoration {
#override
BoxPainter createBoxPainter([VoidCallback? onChanged]) {
return _TopIndicatorBox();
}
}
class _TopIndicatorBox extends BoxPainter {
#override
void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) {
Paint _paint = Paint()
..color = Colors.cyan
..strokeWidth = 5
..isAntiAlias = true;
canvas.drawLine(offset, Offset(cfg.size!.width + offset.dx, 0), _paint);
}
}
Then pass the decoration to the TapBar using TapBar(indicator: TopIndicator ...).
To use the TabBar as the Scaffold.bottomNavigationBar, you will most likely want to wrap it in a Material to apply a background color:
Scaffold(
bottomNavigationBar: Material(
color: Colors.white,
child: TabBar(
indicator: TopIndicator(),
tabs: const <Widget>[
Tab(icon: Icon(Icons.home_outlined), text: 'HOME'),
...
],
),
),
...
)
Thanks Ara Kurghinyan for the original idea.
Column(
children: [
pageIndex == 2
? Container(
height: 5.w,
width: 35.h,
alignment: Alignment.center,
// margin: const EdgeInsets.only(left: 5),
decoration: const BoxDecoration(
color: Colors.teal,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(
3,
),
bottomRight: Radius.circular(3)),
),
// height: 5,
// width: 35,
)
: SizedBox(
height: 5.w,
width: 35.h,
),
SizedBox(
height: 4.h,
),
Flexible(
child: Container(
height: 25.h,
width: 25.w,
// alignment: Alignment.lerp(
// Alignment.bottomLeft, Alignment.bottomRight, 1),
decoration: BoxDecoration(
// color: Colors.red,
border: Border.all(
width: 1,
color: Colors.black,
),
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
),
child: IconButton(
iconSize: 25,
alignment: Alignment.center,
padding: const EdgeInsets.only(top: 4, bottom: 4),
visualDensity:
const VisualDensity(horizontal: -4, vertical: -4),
enableFeedback: false,
onPressed: () {
setState(() {
pageIndex = 2;
});
},
icon: pageIndex == 2
? Image.asset(
'assets/icons/icons8-alarm-50.png',
height: 24.h,
color: Colors.black,
// size: 35.sm,
)
: Image.asset(
'assets/icons/icons8-alarm-50.png',
color: Colors.black,
// size: 35.sm,
)),
),
),
pageIndex == 2
? Container(
height: 15.h,
width: 60.w,
alignment: Alignment.lerp(
Alignment.centerLeft, Alignment.centerRight, 0.75),
child: Text(
'Reminder',
style: GoogleFonts.lato(
textStyle: const TextStyle(
fontSize: 12, fontWeight: FontWeight.bold),
),
),
)
: Container(),
],
),
I am trying to resize the app bar but no change to make the width perfect for the icons to fit.
This is the code that I am using for it
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:tariffo/Detail.dart';
import 'package:tariffo/favoriteProviders.dart';
import 'package:tariffo/messages_list.dart';
import 'package:bubble_bottom_bar/bubble_bottom_bar.dart';
import 'HomePage.dart';
class BarDetail extends StatefulWidget {
#override
_BarDetailState createState() => _BarDetailState();
}
class _BarDetailState extends State<BarDetail> {
int currentIndex;
#override
void initState() {
super.initState();
currentIndex = 0;
}
changePage(int index) {
setState(() {
currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Transform.translate(
offset: Offset(0.0, -50),
child: Container(
height: 82,
margin: EdgeInsets.only(left: 20, right: 20),
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(40),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
BubbleBottomBar(
opacity: 0.2,
backgroundColor: Colors.white10,
borderRadius:
BorderRadius.vertical(top: Radius.circular(80.0)),
currentIndex: currentIndex,
hasInk: true,
inkColor: Colors.black12,
hasNotch: true,
onTap: (index) {
if (index == 1)
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FavoriteProviders()),
);
if (index == 2)
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Searchbar()),
);
if (index == 3)
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MessageList()),
);
},
elevation: 100,
items: <BubbleBottomBarItem>[
BubbleBottomBarItem(
backgroundColor: Colors.blue,
icon: Icon(
Icons.dashboard,
color: Colors.black,
size: 20,
),
activeIcon: Icon(Icons.dashboard,
color: Colors.blue, size: 20),
title: Text(
"Home",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 15),
),
),
BubbleBottomBarItem(
backgroundColor: Colors.red,
icon: Icon(Icons.favorite_border,
color: Colors.black, size: 20),
activeIcon: Icon(Icons.dashboard,
color: Colors.red, size: 20),
title: Text("Saved")),
BubbleBottomBarItem(
backgroundColor: Colors.red,
icon: Icon(Icons.whatshot,
color: Colors.black, size: 20),
activeIcon: Icon(Icons.dashboard,
color: Colors.red, size: 20),
title: Text("Search")),
BubbleBottomBarItem(
backgroundColor: Colors.red,
icon: Icon(Icons.send,
color: Colors.black, size: 20),
activeIcon: Icon(Icons.dashboard,
color: Colors.red, size: 20),
title: Text("Messages")),
]),
],
))));
}
}
Any idea what I should change? the height of the container ? the border radius? It's about the elevation? This app bar is only on my homepage.
[1]: https://i.stack.imgur.com/ZDjNv.png
I would say to remove the Column, the height of the container, and change the margin to all :
margin: EdgeInsets.all(20),
If you need to align some stuff :
How to align single widgets in Flutter?
EDIT :
Using the example from the package (bubble_bottom_bar) works pretty well :
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
backgroundColor: Colors.red,
bottomNavigationBar: BarDetail(),
),
);
}
}
class BarDetail extends StatefulWidget {
#override
_BarDetailState createState() => _BarDetailState();
}
class _BarDetailState extends State<BarDetail> {
int currentIndex;
#override
void initState() {
super.initState();
currentIndex = 0;
}
changePage(int index) {
setState(() {
currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return BubbleBottomBar(
// backgroundColor: Colors.red,
opacity: 0.2,
currentIndex: currentIndex,
onTap: changePage,
borderRadius: BorderRadius.vertical(top: Radius.circular(50)),
elevation: 8,
hasNotch: true,
hasInk: true,
inkColor: Colors.black12,
items: <BubbleBottomBarItem>[
BubbleBottomBarItem(
backgroundColor: Colors.red,
icon: Icon(
Icons.dashboard,
color: Colors.black,
),
activeIcon: Icon(
Icons.dashboard,
color: Colors.red,
),
title: Text("Home")),
BubbleBottomBarItem(
backgroundColor: Colors.deepPurple,
icon: Icon(
Icons.access_time,
color: Colors.black,
),
activeIcon: Icon(
Icons.access_time,
color: Colors.deepPurple,
),
title: Text("Logs")),
BubbleBottomBarItem(
backgroundColor: Colors.indigo,
icon: Icon(
Icons.folder_open,
color: Colors.black,
),
activeIcon: Icon(
Icons.folder_open,
color: Colors.indigo,
),
title: Text("Folders")),
BubbleBottomBarItem(
backgroundColor: Colors.green,
icon: Icon(
Icons.menu,
color: Colors.black,
),
activeIcon: Icon(
Icons.menu,
color: Colors.green,
),
title: Text("Menu"))
],
);
}
}