flutter: how to create bottom navigation bar like this - flutter

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;
});
},
),
),
],
),
),
),
);
}
}

Related

How to call setsate function from a different widget?

Well, I am coding a chatbot-like page in my app. But, I am stuck at calling setState function for page inside of chatBubble widget. Here is my page as MedicBot and chat question code as FirstQuestion. What I do want to do that whenever, user triggers radio tile's on tap condition. It should be trigger setState function in MedicBot, any suggestions?
import 'package:medicte/assets/back_button.dart';
import 'package:medicte/assets/first_question.dart';
class MedicBot extends StatefulWidget {
const MedicBot({Key? key}) : super(key: key);
#override
State<MedicBot> createState() => _MedicBotState();
}
class _MedicBotState extends State<MedicBot> {
late final List<Widget> _messages;
late final List<dynamic> botMessages;
FocusNode _focusNode = FocusNode();
setMainState() {
print('bum');
this.setState(() {});
}
#override
void initState() {
print('bumbeyarag');
botMessages = [
_buildChatBubbles(
widget: SizedBox.shrink(),
text:
'Do you have further medical information you can share? (e.g. lab results)',
userControl: false),
_buildChatBubbles(
widget: FirstQuestion(
focus: _focusNode,
radioButtons: ['1-2 weeks', 'A Month', '1-3 Months', 'Other'],
setMainState: setMainState,
),
text: 'Where do you currently live?',
userControl: false),
_buildChatBubbles(
widget: FirstQuestion(
focus: _focusNode,
radioButtons: [
'Online Consultation',
'Second Opinion',
'A treatment cost',
'Other'
],
setMainState: setMainState,
),
text: 'How soon do you want to get the treatment done?',
userControl: false),
_buildChatBubbles(
widget: FirstQuestion(
focus: _focusNode,
radioButtons: ['Yes', 'No'],
setMainState: () {
setState(() {});
},
),
text: 'What service are you looking for?',
userControl: false),
_buildChatBubbles(
widget: FirstQuestion(
focus: _focusNode,
radioButtons: [],
setMainState: () {
setState(() {});
},
),
text: 'Have you already spoken a doctor?',
userControl: false),
_buildChatBubbles(
text: 'Which treatment are you interested in?',
userControl: false,
widget:
const Text('Enter a treatment name (e.g Hair Transplant, IVF)')),
_buildChatBubbles(
text: 'You are inquiring for',
userControl: false,
widget: FirstQuestion(
radioButtons: const ['Myself', 'For someone else'],
focus: _focusNode,
setMainState: () {
setState(() {});
},
)),
];
_messages = [
const SizedBox(
height: 1,
),
const SizedBox(
height: 10,
)
];
super.initState();
}
final TextEditingController _controller = TextEditingController();
bool value = false;
#override
Widget build(BuildContext context) {
if (botMessages.isNotEmpty) {
_messages.insert(1, botMessages.removeLast());
}
return Scaffold(
bottomSheet: Container(
color: Colors.white30,
child: Padding(
padding: const EdgeInsets.only(bottom: 30, right: 15, left: 15),
child: TextFormField(
focusNode: _focusNode,
controller: _controller,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(25),
),
hintText: 'Type your message',
suffixIcon: IconButton(
onPressed: () {
print(_controller.text);
print(_controller.value);
setState(() {
_messages.insert(
1,
_buildChatBubbles(
text: _controller.text,
userControl: true,
widget: const SizedBox.shrink()));
_controller.clear();
});
},
icon: const Icon(Icons.send),
),
),
),
),
),
appBar: AppBar(
leadingWidth: 101,
backgroundColor: Colors.blue.shade300,
leading: Row(
children: [
const BackWardButton(),
ClipRRect(
borderRadius: BorderRadius.circular(1000),
child: Container(
color: Colors.white,
child: Image.asset(
'lib/images/Lovepik_com-401792159-medical-robot.png',
height: 53,
width: 53),
),
),
],
),
title: const Text(
"MedicBot",
style: TextStyle(color: Colors.black54),
),
),
body: SafeArea(
minimum:
const EdgeInsets.only(top: 2, left: 10, right: 10, bottom: 90),
child: ListView.builder(
itemCount: _messages.length,
reverse: true,
itemBuilder: ((context, index) {
return _messages[index];
}),
)));
}
}
class _buildChatBubbles extends StatelessWidget {
bool userControl;
String text;
Widget widget;
_buildChatBubbles(
{required this.widget,
required this.text,
required this.userControl,
super.key});
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 10),
child: Row(
mainAxisAlignment:
userControl ? MainAxisAlignment.end : MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
userControl
? const SizedBox.shrink()
: Container(
margin: const EdgeInsets.only(right: 10),
child: const CircleAvatar(
radius: 20,
backgroundImage: AssetImage(
'lib/images/Lovepik_com-401792159-medical-robot.png'),
),
),
Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.4,
maxWidth: MediaQuery.of(context).size.width * 0.6),
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: userControl ? Colors.green.shade300 : Colors.blue.shade300,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 7,
offset: const Offset(0, 3), // changes position of shadow
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
userControl ? 'You' : 'Medicte Bot',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 5),
Flexible(
child: Text(
text,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
),
),
),
widget
],
),
),
],
),
);
;
}
}
import 'package:flutter/material.dart';
import 'package:group_button/group_button.dart';
import 'package:medicte/pages/chat_ui.dart';
// ignore: must_be_immutable
class FirstQuestion extends StatefulWidget {
List<String> radioButtons;
FocusNode focus;
void Function() setMainState;
FirstQuestion(
{required this.setMainState,
required this.focus,
required this.radioButtons,
Key? key})
: super(key: key);
#override
State<FirstQuestion> createState() => _FirstQuestionState();
}
class _FirstQuestionState extends State<FirstQuestion> {
late GroupButtonController _radioController;
// ignore: prefer_typing_uninitialized_variables
late final _radioButtons;
#override
void initState() {
_radioButtons = widget.radioButtons;
_radioController = GroupButtonController(
selectedIndexes: [0, 1, 2, 3],
);
super.initState();
}
#override
Widget build(BuildContext context) {
return GroupButton(
controller: _radioController,
isRadio: true,
options: const GroupButtonOptions(groupingType: GroupingType.column),
buttons: _radioButtons,
buttonIndexedBuilder: (selected, index, context) {
return RadioTile(
title: _radioButtons[index],
selected: _radioController.selectedIndex,
index: index,
onTap: () {
print(_radioButtons[index].toString());
widget.setMainState();
_radioController.selectIndex(index);
/* Future.delayed(Duration(seconds: 1), () {
widget.setMainState();
}); */
},
);
},
onSelected: (val, i, selected) {
print('object');
});
}
}
class RadioTile extends StatelessWidget {
const RadioTile({
Key? key,
required this.selected,
required this.onTap,
required this.index,
required this.title,
}) : super(key: key);
final String title;
final int index;
final int? selected;
final VoidCallback onTap;
#override
Widget build(BuildContext context) {
return ListTile(
title: Text(title),
onTap: onTap,
leading: Radio<int>(
groupValue: selected,
value: index,
onChanged: (val) {
print(val);
onTap();
},
),
);
}
}
Try something like this. This is the code snippet of an application of mine. I used StatefulBuilder as the parent of the widgets I want to update and I sent the setState parameter to the widget where I trigger.
import 'package:flutter/material.dart';
class CryptoassetsPage extends StatefulWidget {
const CryptoassetsPage({Key? key}) : super(key: key);
#override
_CryptoassetsPageState createState() => _CryptoassetsPageState();
}
class _CryptoassetsPageState extends State<CryptoassetsPage> {
#override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).backgroundColor,
child: SingleChildScrollView(
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
//My other class/widget
return OrderOptions(setState);
}),
),
);
}
}
class OrderOptions extends StatefulWidget {
const OrderOptions(this.setState, {Key? key}) : super(key: key);
final StateSetter setState;
#override
_OrderOptionsState createState() => _OrderOptionsState();
}
class _OrderOptionsState extends State<OrderOptions> {
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
StateSetter setState = widget.setState;
setState(() {});
},
);
}
}

why is (_selected) in Widged _button undfined

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.

Checkbox doesn't change when clicked in dropdownbutton

I am using DropdownButton and I am facing the following issue. I'm using a checkbox in elements, but when I click on an element, I don't get a checkmark indicating that the checkbox has been clicked. As a result, I need to close and reopen it, and then I will see the changes that were clicked on the "checkbox". The second problem is that when I select one element, all elements are selected for me. As a final result, I need to get so that I can select an element and the checkbox is immediately marked, if 2 elements are needed, then two, and so on. Tell me how to fix these problems, I will be grateful for the help?
dropdown
class DropdownWidget extends StatefulWidget {
List<String> items;
SvgPicture? icon;
double width;
DropdownWidget({
Key? key,
required this.items,
required this.icon,
required this.width,
}) : super(key: key);
#override
State<DropdownWidget> createState() => _DropdownWidgetState();
}
class _DropdownWidgetState extends State<DropdownWidget> {
String? selectedValue;
bool isChecked = false;
#override
void initState() {
super.initState();
if (widget.items.isNotEmpty) {
selectedValue = widget.items[1];
}
}
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
child: DropdownButtonHideUnderline(
child: DropdownButton2(
items: widget.items
.map((item) => DropdownMenuItem<String>(
value: item,
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: constants.Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: Center(
child: Row(
children: [
if (item == selectedValue)
const SizedBox(
width: 0,
),
Expanded(
child: Text(
item,
style: constants.Styles.smallTextStyleWhite,
),
),
Checkbox(
checkColor: Colors.black,
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
),
],
),
),
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
itemHeight: 47,
dropdownMaxHeight: 191,
dropdownWidth: 140,
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: constants.Colors.purpleMain,
),
color: constants.Colors.greyDark,
),
selectedItemBuilder: (context) {
return widget.items.map(
(item) {
return Row(
children: [
widget.icon ?? const SizedBox(),
const SizedBox(width: 8),
Text(
item,
style: constants.Styles.bigBookTextStyleWhite,
),
],
);
},
).toList();
},
),
),
);
}
}
items
final List<String> items = const [
"All EV's",
'Main EV',
'<EV2>',
];
I hope this example explains the concept. For simplcity I made simple a new file, run it and see the results:
Then main idea in two lists, _checkList contain values of the CheckBox and _selectedList handles the main dropdown widget to show the selection.
Feel free to ask any questions and I'm happy to help
import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
const TestPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const AnimationDemo(number: 5);
}
}
class AnimationDemo extends StatefulWidget {
const AnimationDemo({Key? key, this.number = 2}) : super(key: key);
final int number;
#override
State<AnimationDemo> createState() => _AnimationDemoState();
}
class _AnimationDemoState extends State<AnimationDemo> {
late List<bool> _checkList;
late List<int> _selectedIndex;
bool _isOpen = false;
#override
void initState() {
_checkList = List.filled(widget.number, false);
_selectedIndex = <int>[];
super.initState();
}
List<DropDownItem> generateItems() {
var tmp = <DropDownItem>[];
for (var i = 0; i < _checkList.length; i++) {
tmp.add(DropDownItem(
isChecked: _checkList[i],
onChanged: (value) {
setState(() {
_checkList[i] = value!;
if (value && !_selectedIndex.contains(i)) {
_selectedIndex.add(i);
} else {
_selectedIndex.remove(i);
}
});
},
));
}
return tmp;
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Expanded(
child: Text((_selectedIndex.isEmpty)
? 'Nothing Selected'
: _selectedIndex.join(',')),
),
GestureDetector(
onTap: () {
setState(() {
_isOpen = !_isOpen;
});
},
child: const Icon(Icons.arrow_downward),
),
],
),
AnimatedOpacity(
opacity: (_isOpen) ? 1 : 0,
duration: const Duration(milliseconds: 300),
child: Column(
mainAxisSize: MainAxisSize.min,
children: generateItems(),
),
)
],
),
);
}
}
class DropDownItem extends StatelessWidget {
final bool isChecked;
final Function(bool?)? onChanged;
const DropDownItem({Key? key, this.onChanged, this.isChecked = false})
: super(key: key);
#override
Widget build(BuildContext context) {
return Row(
children: [
const Expanded(child: Text('Demo item')),
Checkbox(value: isChecked, onChanged: onChanged)
],
);
}
}
Here's how to achieve the Multiselect dropdown with DropdownButton2:
final List<String> items = [
'Item1',
'Item2',
'Item3',
'Item4',
];
List<String> selectedItems = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
hint: Align(
alignment: AlignmentDirectional.center,
child: Text(
'Select Items',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).hintColor,
),
),
),
items: items.map((item) {
return DropdownMenuItem<String>(
value: item,
//disable default onTap to avoid closing menu when selecting an item
enabled: false,
child: StatefulBuilder(
builder: (context, menuSetState) {
final _isSelected = selectedItems.contains(item);
return InkWell(
onTap: () {
_isSelected
? selectedItems.remove(item)
: selectedItems.add(item);
//This rebuilds the StatefulWidget to update the button's text
setState(() {});
//This rebuilds the dropdownMenu Widget to update the check mark
menuSetState(() {});
},
child: Container(
height: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: [
_isSelected
? const Icon(Icons.check_box_outlined)
: const Icon(Icons.check_box_outline_blank),
const SizedBox(width: 16),
Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
],
),
),
);
},
),
);
}).toList(),
//Use last selected item as the current value so if we've limited menu height, it scroll to last item.
value: selectedItems.isEmpty ? null : selectedItems.last,
onChanged: (value) {},
buttonHeight: 40,
buttonWidth: 140,
itemHeight: 40,
itemPadding: EdgeInsets.zero,
selectedItemBuilder: (context) {
return items.map(
(item) {
return Container(
alignment: AlignmentDirectional.center,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
selectedItems.join(', '),
style: const TextStyle(
fontSize: 14,
overflow: TextOverflow.ellipsis,
),
maxLines: 1,
),
);
},
).toList();
},
),
),
),
);
}
Also, I've added it as an example to the package doc "Example 4" so you can get back to it later.

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