why is (_selected) in Widged _button undfined - flutter

in the Widget _button it says:
Undefined name '_selected'.
Try correcting the name to one that is defined, or defining the name.dartundefined_identifier
But I defined at in Widget section please help
or say me what do i wrong
it is the same with _setState
class NavBar extends StatefulWidget {
const NavBar({Key? key}) : super(key: key);
#override
_NavBarState createState() => _NavBarState();
}
class _NavBarState extends State<NavBar> {
final _palette = AppTheme.palette;
int _selected = 0;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: _palette.primaryColor,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_button(
index: 0,
icon: Icons.home,
selectedIndex: _selected,
),
_button(
index: 1,
icon: Icons.favorite_border_outlined,
selectedIndex: _selected,
),
],
),
);
}
}
on the same page is the Widget _button
Widget _button({
required int index,
required IconData icon,
VoidCallback? onPressed,
int selectedIndex: 0,
}) {
bool isSelected = selectedIndex == index;
return Material(
color: isSelected ? AppTheme.palette.buttonOverlay : Colors.transparent,
borderRadius: BorderRadius.circular(13),
clipBehavior: Clip.antiAlias,
child: IconButton(
visualDensity: VisualDensity.compact,
icon: Icon(
icon,
color: isSelected
? AppTheme.palette.secondaryColor
: AppTheme.palette.buttonOverlay,
),
onPressed: () {
_selected = index;
onPressed?.call();
setState(() {});
},
),
);
}

...on the same page is the Widget _button
You need to make sure that _button is within your NavBar class. It should look like this:
class NavBar extends StatefulWidget {
const NavBar({Key? key}) : super(key: key);
#override
_NavBarState createState() => _NavBarState();
}
class _NavBarState extends State<NavBar> {
final _palette = AppTheme.palette;
int _selected = 0;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: _palette.primaryColor,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_button(
index: 0,
icon: Icons.home,
selectedIndex: _selected,
),
_button(
index: 1,
icon: Icons.favorite_border_outlined,
selectedIndex: _selected,
),
],
),
);
}
Widget _button({
required int index,
required IconData icon,
VoidCallback? onPressed,
int selectedIndex: 0,
}) {
bool isSelected = selectedIndex == index;
return Material(
color: isSelected ? AppTheme.palette.buttonOverlay : Colors.transparent,
borderRadius: BorderRadius.circular(13),
clipBehavior: Clip.antiAlias,
child: IconButton(
visualDensity: VisualDensity.compact,
icon: Icon(
icon,
color: isSelected
? AppTheme.palette.secondaryColor
: AppTheme.palette.buttonOverlay,
),
onPressed: () {
_selected = index;
onPressed?.call();
setState(() {});
},
),
);
}
}

Make sure your _button method is inside the _NavBarState class, otherwise you can't access the global data inside it.

Related

I need selectable buttoon in flutter

what i get_____whai i wantbut when i use ToggleButttons i cant change its shape(i need rounded), and cant put more distance beetwen buttons. Toggle button is list in which put icons. But how i can make selectabe(only one of thr buuton) without toggle like in exaple or with toglleButoon
class MyToggleButtonsState extends State<MyToggleButtons> {
List<bool> iSselected = List.generate(4,(index)=> false);
List<IconData> icon = [MyFlutterApp.mobile,Icons.computer,Icons.monitor_heart,Icons.collections_bookmark_sharp ];
#override
Widget build(BuildContext context) {
return ToggleButtons(
selectedColor: Colors.white,
renderBorder: false,
isSelected: iSselected,
fillColor: Colors.orange,
onPressed: (int newIndex) {
setState(() {
for(int index = 0; index < iSselected.length; index++){
if(index == newIndex){
iSselected[index] = true;
} else{
iSselected[index] = false;
}
}
});
},
children: [
CustomIcon(
radius: BorderRadius.circular(32.0),
isSelected: iSselected[0],
icon: const Icon(MyFlutterApp.mobile),
),
CustomIcon(
radius: BorderRadius.circular(32.0),
isSelected: iSselected[1],
icon: const Icon(Icons.computer)
),
CustomIcon(
radius: BorderRadius.circular(32.0),
isSelected: iSselected[2],
icon: const Icon(Icons.monitor_heart)
),
CustomIcon(
radius: BorderRadius.circular(32.0),
isSelected: iSselected[3],
icon: const Icon(Icons.collections_bookmark_sharp)
)
]
);[What i want][1][What i can][1]
}
}
Thank you very much
You can achieve this by doing the following!
class CustomPageWithToggle extends StatefulWidget {
const CustomPageWithToggle({Key? key}) : super(key: key);
#override
State<CustomPageWithToggle> createState() => _CustomPageWithToggleState();
}
class _CustomPageWithToggleState extends State<CustomPageWithToggle> {
List<bool> isSelected = List.generate(5, (index) => false);
List<IconData> icons = [Icons.phone_android, Icons.computer, Icons.monitor_heart, Icons.menu_book, Icons.fastfood];
List<String> texts = ['Phones', 'Computers', 'Health', 'Books', 'Food'];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Example'),
),
backgroundColor: const Color.fromARGB(255, 218, 218, 218),
body: Column(
children: [
const SizedBox(
height: 10,
),
CustomToggle(
icons: icons,
texts: texts,
setStateFunction: setState,
isSelected: isSelected,
),
// Put Your Content Here
],
),
);
}
}
class CustomToggle extends StatelessWidget {
final List<IconData> icons;
final List<String> texts;
final Function setStateFunction;
final List<bool> isSelected;
const CustomToggle({
Key? key,
required this.icons,
required this.texts,
required this.setStateFunction,
required this.isSelected,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
// You should use this widget: SingleChildScrollView if your ToggleButtons are too long and overflow the screen.
// This makes it scrollable. If yours will not overflow, you can remove this widget.
scrollDirection: Axis.horizontal,
child: ToggleButtons(
isSelected: isSelected,
onPressed: (index) {
setStateFunction(() {
for (int i = 0; i < isSelected.length; i++) {
if (i == index) {
isSelected[i] = true;
} else {
isSelected[i] = false;
}
}
});
},
renderBorder: false,
fillColor: Colors.transparent,
splashColor: Colors.orange,
// Include other design properties if needed.
children: List<Widget>.generate(icons.length, (index) {
return CustomButton(
text: texts[index],
icondata: icons[index],
isSelected: isSelected[index],
);
}),
),
);
}
}
class CustomButton extends StatelessWidget {
final String text;
final IconData icondata;
final bool isSelected;
const CustomButton({
Key? key,
required this.text,
required this.icondata,
this.isSelected = false,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: [
Container(
width: 70,
height: 70,
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: isSelected ? Colors.orange : Colors.white,
shape: BoxShape.circle,
),
child: Icon(
icondata,
color: isSelected ? Colors.white : Colors.grey,
),
),
const SizedBox(height: 10),
Text(
text,
style: TextStyle(
color: isSelected ? Colors.orange : Colors.grey,
),
),
],
);
}
}
Explanation:
Using the ToggleButtons widget is the right choice for this. But as you said, using the properties of ToggleButtons can't create the button design you want. Therefore you have to provide your own custom button to the ToggleButtons child propaties.
Also, one important change I made to your code is, your code has the state controlled in the MyToggleButtons. But, mine is controlled at the Parent Widget(CustomPageWithToggle) not the CustomToggle. Yours will also work for your Toggle button but, the widget outside(parent widget, etc) can't access the isSelected list (Which probably you may want to use outside the toggle button). Notice with my code that any widget inside CustomPageWithToggle can access the isSelected variable.
Result:
If you don't understand or have questions leave a comment and I'll answer!

How to add navigation in my Bottom Navigation Bar

I'm new to Flutter, I want to create a navigation bar that can change color when I tap on it. I'm done with that part. Now I'm working on how to navigate to the other page when I tap the navigation bar.
This is my code.
I don't know how to implement the navigation part in my code. I confuse with isSelected and selectedIndex. Hope someone can help me on this and clarify for my better understanding in Flutter.
class BottomNavBar extends StatefulWidget {
#override
State<BottomNavBar> createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
int _isSelected = 0;
final List<BottomNavItem> _listBottomNavItems = const [
BottomNavItem(title:'Home', icon: Icons.home),
BottomNavItem(title:'Activity', icon: Icons.receipt),
BottomNavItem(title:'Wallet', icon: Icons.credit_card),
BottomNavItem(title:'Notification', icon: Icons.notifications),
BottomNavItem(title:'Settings', icon: Icons.person),
];
#override
Widget build(BuildContext context) {
return
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(_listBottomNavItems.length,
(index){
return BottomNavItem(
title: _listBottomNavItems[index].title,
icon: _listBottomNavItems[index].icon,
isSelected: _isSelected == index,
onTap: (){
setState((){
_isSelected = index;
});
}
);
})
);
}
}
class BottomNavItem extends StatelessWidget {
final String title;
final IconData icon;
final bool? isSelected;
final Function()? onTap;
const BottomNavItem({
required this.title,
required this.icon,
this.isSelected,
this.onTap
});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.all(5),
width: 50,
height: 40,
decoration: BoxDecoration(
color: isSelected == true ? Colors.black87: Colors.transparent,
borderRadius: BorderRadius.circular(10),
),
child: Column(
children: [
Icon(icon, color: isSelected == true ? Colors.white: Colors.black87, size: 17),
const SizedBox(height: 5,),
Text(
title,
style: TextStyle(
fontSize: 7,
fontWeight: FontWeight.bold,
color: isSelected == true ? Colors.white: Colors.black87
),
)
],
)
)
);
}
}
You can add the page in BottomNavItem like this
class BottomNavItem extends StatelessWidget {
final String title;
final IconData icon;
final bool? isSelected;
final Function()? onTap;
final Widget page;
const BottomNavItem({
required this.title,
required this.icon,
required this.page,
this.isSelected,
this.onTap
});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
onTap!();
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => page,
),
);
},
child: Container(
padding: const EdgeInsets.all(5),
width: 50,
height: 40,
decoration: BoxDecoration(
color: isSelected == true ? Colors.black87: Colors.transparent,
borderRadius: BorderRadius.circular(10),
),
child: Column(
children: [
Icon(icon, color: isSelected == true ? Colors.white: Colors.black87, size: 17),
const SizedBox(height: 5,),
Text(
title,
style: TextStyle(
fontSize: 7,
fontWeight: FontWeight.bold,
color: isSelected == true ? Colors.white: Colors.black87
),
)
],
)
)
);
}
}
then just add your page in list.
final List<BottomNavItem> _listBottomNavItems = const [
BottomNavItem(title:'Home', icon: Icons.home, page: Home()),
BottomNavItem(title:'Activity', icon: Icons.receipt, page: Activity()),
BottomNavItem(title:'Wallet', icon: Icons.credit_card, page: Wallet()),
BottomNavItem(title:'Notification', icon: Icons.notifications, page: Notification()),
BottomNavItem(title:'Settings', icon: Icons.person, page: Settings()),
];
Hope this works
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(_listBottomNavItems.length,
(index){
return BottomNavItem(
title: _listBottomNavItems[index].title,
icon: _listBottomNavItems[index].icon,
isSelected: _isSelected == index,
onTap: (){
setState((){
_isSelected = index;
if(_listBottomNavItems[index].title == 'Home') {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
Home(),
));
} else if(_listBottomNavItems[index].title == 'Activity') {
//write accordingly
}
});
}
);
})
);

Function callback to change text color (just for one) | Flutter

I'm trying to create a SideMenu with different SideMenuItems.
For that I created a new class and want to update the color of Text when the SideMenuItem is clicked. For that I want to transfer the activeState and all that stuff you see in the code below:
The use of my class in the Widget:
bool isActive = false;
...
SideMenuItem(
icon: Icon(
Icons.inbox,
size: 20,
color: isActive ? kPrimaryColor : kGrayColor,
),
activeState: isActive,
title: "Archiv",
toggleActiveState: (activeState) {
setState(() {
isActive = !activeState;
});
},
),
And here is my class:
import 'package:flutter/material.dart';
import 'package:gastronomy/constants.dart';
class SideMenuItem extends StatelessWidget {
// ignore: prefer_const_constructors_in_immutables
SideMenuItem({
Key? key,
required this.activeState,
this.itemCount = 0,
this.showBorder = true,
#required this.icon,
#required this.title,
required this.toggleActiveState,
}) : super(key: key);
final bool activeState;
final bool showBorder;
final int itemCount;
final Icon? icon;
final String? title;
final Function(bool) toggleActiveState;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: kDefaultPadding),
child: InkWell(
onTap: () {
toggleActiveState(activeState);
},
child: Row(
children: [
const SizedBox(width: 15),
const SizedBox(width: kDefaultPadding / 4),
Expanded(
child: Container(
padding: const EdgeInsets.only(bottom: 15, right: 5),
decoration: showBorder
? const BoxDecoration(
border: Border(
bottom: BorderSide(color: Color(0xFFDFE2EF)),
),
)
: null,
child: Row(
children: [
icon!,
const SizedBox(width: kDefaultPadding * 0.75),
Text(
title!,
style: Theme.of(context).textTheme.button?.copyWith(
color: activeState ? kTextColor : kGrayColor,
),
),
const Spacer(),
// if (itemCount != null) CounterBadge(count: itemCount)
],
),
),
),
],
),
),
);
}
}
I ended up with that pieces of code but well, how you might know, all SideMenuItems change there color when I click one.
I'm pretty new at using this way of code so I would be thankful to all informations you can include into your answer.
One option is to render all the menu items through a map function and compare each item with the selected option, like in the example below:
import 'package:flutter/material.dart';
class MenuExample extends StatefulWidget {
const MenuExample({Key? key}) : super(key: key);
#override
_MenuExampleState createState() => _MenuExampleState();
}
class _MenuExampleState extends State<MenuExample> {
List<String> menuOptions = const ['Item 1', 'Item 2', 'Item 3'];
String selectedOption = '';
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(
backgroundColor: Colors.amber,
child: ListView(
children: menuOptions.map((menuOption) {
return InkWell(
onTap: () => setState(() {
selectedOption = menuOption;
}),
child: MenuItem(
name: menuOption,
isSelected: menuOption == selectedOption,
),
);
}).toList()),
),
);
}
}
class MenuItem extends StatelessWidget {
const MenuItem({Key? key, this.isSelected = false, required this.name})
: super(key: key);
final bool isSelected;
final String name;
#override
Widget build(BuildContext context) {
return ListTile(
title: Text(
name,
style: TextStyle(
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal),
),
);
}
}

How to call a function from stateless Widget that points to state class function?

I am trying to create a responsive chatbot with quick replies. I want to make a button on pressed function call to another class's function. I tried using the callback. But i think i am doing something wrong. Kindly help me.
typedef void mycallback(String label);
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
User? user = FirebaseAuth.instance.currentUser;
UserModel loggedInUser = UserModel();
late DialogFlowtter dialogFlowtter;
final TextEditingController messageController = TextEditingController();
#override
void initState() {
super.initState();
DialogFlowtter.fromFile().then((instance) => dialogFlowtter = instance);
}
#override
Widget build(BuildContext context) {
var themeValue = MediaQuery.of(context).platformBrightness;
Body(
hi: sendMessage,
);
return Scaffold(
backgroundColor: themeValue == Brightness.dark
? HexColor('#262626')
: HexColor('#FFFFFF'),
appBar: AppBar(
//app bar ui
),
actions: [
//list if widget in appbar actions
PopupMenuButton(
icon: Icon(Icons.menu),
color: Colors.blue,
itemBuilder: (context) => [
PopupMenuItem<int>(
value: 0,
child: Text(
"Log out",
style: TextStyle(color: Colors.white),
),
),
],
onSelected: (item) => {logout(context)},
),
],
),
body: SafeArea(
child: Column(
children: [
Expanded(child: Body(messages: messages)),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: Row(
children: [
Expanded(
child: TextFormField(
controller: messageController,
style: TextStyle(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black,
fontFamily: 'Poppins'),
decoration: new InputDecoration(
enabledBorder: new OutlineInputBorder(
borderSide: new BorderSide(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black),
borderRadius: BorderRadius.circular(15)),
hintStyle: TextStyle(
color: themeValue == Brightness.dark
? Colors.white54
: Colors.black54,
fontSize: 15,
fontStyle: FontStyle.italic,
),
labelStyle: TextStyle(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black),
hintText: "Type here...",
),
),
),
IconButton(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black,
icon: Icon(Icons.send),
onPressed: () {
sendMessage(messageController.text);
messageController.clear();
},
),
],
),
),
],
),
),
);
}
void sendMessage(String text) async {
if (text.isEmpty) return;
setState(() {
//do main function
});
}
}
The class from where i want to call the function
class Body extends StatelessWidget {
final List<Map<String, dynamic>> messages;
final mycallback? hi;
const Body({
Key? key,
this.messages = const [],
this.buttons = const [],
this.hi,
this.onPressed,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.separated(
itemBuilder: (context, i) {
var obj = messages[messages.length - 1 - i];
Message message = obj['message'];
bool isUserMessage = obj['isUserMessage'] ?? false;
String label = obj['label'];
return Row(
mainAxisAlignment:
isUserMessage ? MainAxisAlignment.end : MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
_MessageContainer(
message: message,
isUserMessage: isUserMessage,
),
ElevatedButton(
child: Text(label),
onPressed: () => {hi ?? (label)},//This is where i want to call
style: ElevatedButton.styleFrom(
primary: Colors.blueAccent,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
textStyle: TextStyle(fontWeight: FontWeight.bold)),
),
],
);
},
separatorBuilder: (_, i) => Container(height: 10),
itemCount: messages.length,
reverse: true,
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 20,
),
);
}
}
The code runs without errors but nothing happens when i press the buttons.
This is how I'd implement something like that. You're basically asking for a void as parameter inside your widget. Almost like a TextButton or another widget like that.
You can use this with two stateful widets as well, since you're borrowing the function from one to another.
Also I think this would be done better with provider so I suggest you look into it. (I don't have enough experience with it)
https://pub.dev/packages/provider
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int x = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('An app'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('$x'),
TestWidget(onTap: () {
setState(() {
x++;
});
})
],
),
),
);
}
}
class TestWidget extends StatelessWidget {
final VoidCallback onTap;
const TestWidget({Key? key, required this.onTap}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.all(20),
color: Colors.blue,
child: Text('test')),
);
}
}
I found the error.
In the class HomeScreen, I missed this line.
child: Body(
messages: messages,
hi: (text) => {sendMessage(text)}, //this line
)
After adding this line, the callback worked fine!

flutter: how to create bottom navigation bar like this

I want to make a bottom navigation bar exact like this which is in photo but I can't make.
Please help me.
I also want devide section between each part. please help me
You can custom create bottomNavigationBar using BottomAppBar.
Example:
Step 1: Create a statefull widget in this example its called MyHomePage:
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedIndex = 0;
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
//Default is true so this can be ignore/removed
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: Text(widget.title),
),
bottomNavigationBar: BottomAppBar(
child: Container(
height: 56,
padding: EdgeInsets.all(6),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BottomNavigationMenu(
label: 'Home',
isSelected: _selectedIndex == 0,
icon: Icons.home,
onTap: () {
_onItemTapped(0);
},
),
VerticalDivider(),
BottomNavigationMenu(
label: 'Business',
isSelected: _selectedIndex == 1,
icon: Icons.work,
onTap: () {
_onItemTapped(1);
},
),
VerticalDivider(),
BottomNavigationMenu(
label: 'Map',
isSelected: _selectedIndex == 2,
icon: Icons.map_outlined,
onTap: () {
_onItemTapped(2);
},
),
VerticalDivider(),
BottomNavigationMenu(
label: 'Service',
isSelected: _selectedIndex == 3,
icon: Icons.room_service,
onTap: () {
_onItemTapped(3);
},
),
VerticalDivider(),
BottomNavigationMenu(
label: 'Profile',
isSelected: _selectedIndex == 4,
icon: Icons.account_circle,
onTap: () {
_onItemTapped(4);
},
),
],
),
),
),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Center(
child: Text("Demo"),
),
),
);
}
}
Step 2: Creating custom BottomNavigationMenu item using StatelessWidget ie. BottomNavigationMenu:
class BottomNavigationMenu extends StatelessWidget {
final Function()? onTap;
final String label;
final IconData icon;
final bool isSelected;
final Color selectedColor = Colors.green;
final Color defaultColor = Colors.grey;
const BottomNavigationMenu(
{required this.icon,
required this.label,
required this.onTap,
required this.isSelected});
#override
Widget build(BuildContext context) {
return Expanded(
child: InkWell(
onTap: onTap,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
icon,
color: isSelected ? selectedColor : defaultColor,
),
Text(
label,
style: Theme.of(context).textTheme.bodyText2!.copyWith(
color: isSelected ? selectedColor : defaultColor,
),
)
],
),
),
);
}
}
That's it. You can customise your selected color in BottomNavigationMenu.
And this is how it looks: Custom BottomNavigationBar
Result
CustomNavBarItem
class BottomNavIcon extends StatelessWidget {
final IconData iconData;
final bool isSelected;
final String label;
final Function callback;
const BottomNavIcon({
Key? key,
required this.iconData,
required this.isSelected,
required this.label,
required this.callback,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
callback();
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: isSelected ? Colors.green.shade200 : Colors.grey.shade300,
shape: BoxShape.circle,
),
child: Icon(
iconData,
color: isSelected ? Colors.green.shade800 : Colors.grey.shade600,
),
),
Text(
label,
style: TextStyle(
fontSize: 12,
color: isSelected ? Colors.green : Colors.grey,
fontWeight: FontWeight.bold,
),
)
],
),
);
}
}
VerticalDivider Control
get divider => VerticalDivider(
color: Colors.grey.shade300,
endIndent: 4,
indent: 4,
);
Full Widget:
import 'package:flutter/material.dart';
class BottomNavBar extends StatefulWidget {
BottomNavBar({Key? key}) : super(key: key);
#override
_BottomNavBarState createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
int _selectedIndex = 0;
get divider => VerticalDivider(
color: Colors.grey.shade300,
endIndent: 4,
indent: 4,
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Text("Body"),
bottomNavigationBar: BottomAppBar(
child: Container(
//* for padding
height: kBottomNavigationBarHeight + 16,
padding: EdgeInsets.all(8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
BottomNavIcon(
iconData: Icons.home_filled,
isSelected: _selectedIndex == 0,
label: "Home".toUpperCase(),
callback: () {
setState(() {
_selectedIndex = 0;
});
},
),
divider,
BottomNavIcon(
iconData: Icons.business_center,
isSelected: _selectedIndex == 1,
label: "Business".toUpperCase(),
callback: () {
setState(() {
_selectedIndex = 1;
});
},
),
divider,
BottomNavIcon(
iconData: Icons.location_on_outlined,
isSelected: _selectedIndex == 2,
label: "Map".toUpperCase(),
callback: () {
setState(() {
_selectedIndex = 2;
});
},
),
divider,
BottomNavIcon(
iconData: Icons.design_services_outlined,
isSelected: _selectedIndex == 3,
label: "services".toUpperCase(),
callback: () {
setState(() {
_selectedIndex = 3;
});
},
),
divider,
Container(
child: BottomNavIcon(
iconData: Icons.settings,
isSelected: _selectedIndex == 4,
label: "Profile".toUpperCase(),
callback: () {
print("oncalleck $_selectedIndex");
setState(() {
_selectedIndex = 4;
});
},
),
),
],
),
),
),
);
}
}