I have a horizontal list of Categories; e.g. CARS and below it there is a dropdown menu fetch list of models per every CAR selected in the list. So my issue is after i select eg Toyota and the dropdown menu is filled with models eg - Camry, Vits, Caldina, Hilux, That is fine... but is i select one eg Camry and in the list of CARS i select another CAR eg HONDA.. the UI breaks.. can anyone tell me how i can efficiently reuse the same dropdown and just be changing the arraylist it fetchs from even when one item was selectd
I did something similar like this:
For car brand:
int selectedBrandItem;
int selectedModelItem;
int selectedByYearItem;
var listTemp;
Container(
width: _size.width,
height: _size.height* 0.08,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0),
border: Border.all(
color: Theme.greyColor[600]
),
),
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal:10.0),
child: DropdownButton(
hint: Text(allTranslations.text('brand')),
value: selectedBrandItem,
onChanged: (value){
setState(() {
selectedBrandItem = value;
selectedModelItem = null;
selectedByYearItem = null;
});
},
items: (state.response.brandList == null || state.response.brandList == [])?listTemp:state.response.brandList.map((e) =>
DropdownMenuItem(
value: e.id,
child: Text(
e.brandName,
style: TextStyle(
color: Theme.GreyColor,
fontWeight: FontWeight.w400,
fontSize: 16.0
),
)
)
).toList()??[],
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down, color: Theme.greyColor[500],),
underline: Container(color: Colors.transparent,),
),
),
);
For car model:
Container(
width: _size.width,
height: _size.height* 0.08,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0),
border: Border.all(
color: Theme.greyColor[600]
),
),
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal:10.0),
child: DropdownButton(
hint: Text(allTranslations.text('model')),
value: selectedModelItem,
onChanged: (value){
setState(() {
selectedModelItem = value;
selectedByYearItem = null;
});
},
items: state.response.modelList.map((e) =>
DropdownMenuItem(
value: e.id,
child: Text(
e.modelName,
style: TextStyle(
color: Theme.GreyColor,
fontWeight: FontWeight.w400,
fontSize: 16.0
),
)
)
).toList()??[],
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down, color: Theme.greyColor[500],),
underline: Container(color: Colors.transparent,),
),
),
);
For car year:
Container(
width: _size.width,
height: _size.height* 0.08,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0),
border: Border.all(
color: Theme.greyColor[600]
),
),
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal:10.0),
child: DropdownButton(
hint: Text(allTranslations.text('year')),
value: selectedByYearItem,
onChanged: (value){
setState(() {
selectedByYearItem = value;
});
},
items: (state.response.yearList == null || state.response.yearList == [] )?listTemp:state.response.yearList .map((e) =>
DropdownMenuItem(
value: e.id,
child: Text(
e.year,
style: TextStyle(
color: Theme.GreyColor,
fontWeight: FontWeight.w400,
fontSize: 16.0
),
)
)
).toList()??[],
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down, color: Theme.greyColor[500],),
underline: Container(color: Colors.transparent,),
),
),
);
Related
My dropdown list has a multi-select feature. I have shown the list and selected Items are saved in an array called selectedClassList. Basically, it's a normal checkbox procedure.
But in the scenario of clicking a value called "any", I need to unselect all other items and need to mark "Any" as selected. The same is for other items, when a user clicks any of the other items, then item "any" should get unselected.
My code is like
DropdownButtonFormField2<dynamic>(
itemHeight: 40,
dropdownOverButton: false,
buttonWidth: double.infinity,
selectedItemHighlightColor: Colors.grey.shade300,
isExpanded: true,
value: widget.value,
dropdownElevation: 0,
itemPadding: const EdgeInsets.only(left: 15),
buttonDecoration: BoxDecoration(
border: Border.all(color: Colors.black87, width: 1),
borderRadius: BorderRadius.circular(5),
),
decoration: const InputDecoration.collapsed(
hintText: '',
border: InputBorder.none,
),
isDense: true,
offset: const Offset(0, -2),
iconSize: 20,
buttonHeight: 50,
buttonPadding: const EdgeInsets.only(left: 15, right: 10),
focusColor: const Color(0xffFFFFFF),
hint: const Text('Select One',
style: TextStyle(
fontSize: 14,
fontFamily: 'Poppins, Regular',
color: Color(0xffAAAAAA))),
style: const TextStyle(
fontSize: 14,
fontFamily: 'Poppins, Regular',
overflow: TextOverflow.ellipsis,
color: Color(0xff121212)),
iconOnClick: AnimatedRotation(
turns: 0.5,
duration: const Duration(milliseconds: 300),
child: Icon(Icons.arrow_down),
),
icon: AnimatedRotation(
turns: 1,
duration: const Duration(milliseconds: 300),
child: Icon(Icons.arrow_up),
),
dropdownDecoration: BoxDecoration(
border: Border.all(
color: Colors.black45,
width: 1,
),
borderRadius: const BorderRadius.all(Radius.circular(5)),
shape: BoxShape.rectangle),
dropdownMaxHeight: 200,
items: getClassDetails.data?.map((item) {
return DropdownMenuItem<dynamic>(
value: item,
enabled: false,
child: StatefulBuilder(
builder: (context, menuSetState) {
var _isSelected = selectedClass!
.where((element) =>
element.settingName == item.settingName)
.toList()
.isNotEmpty;
return InkWell(
onTap: () {
if (item.settingName == "Any") {
selectedClass!.clear();
}
if (_isSelected == true) {
selectedClass!.remove(item);
} else {
selectedClass!.add(item);
}
setState(() {});
menuSetState(() {});
},
child: Row(
children: [
_isSelected
? const Icon(Icons.check_box_outlined)
: const Icon(Icons.check_box_outline_blank),
const SizedBox(width: 16),
Text(
item.settingName.toString(),
style: const TextStyle(
fontSize: 14,
fontFamily: 'Poppins, Regular',
color: Color(0xff121212)),
),
],
),
);
},
),
);
}).toList(),
)
I am not good at explaining things. Kindly let me know if I made any mistake.
I want to add text inside cupertino switch like attached image.. Is there a way to do it?
As of today there is no way to customize the CupertinoSwitch in Flutter out of the box, but hey! there are a number of Plugins in pub.dev that could satisfy your needs, like flutter_switch.
With the following code you can achieve something like what you want:
FlutterSwitch(
showOnOff: true,
value: v,
activeIcon: Text("SELL"),
activeText: "BUY",
inactiveIcon: Text("BUY"),
inactiveText: "SELL",
inactiveColor: Colors.blue,
activeTextFontWeight: FontWeight.normal,
inactiveTextFontWeight: FontWeight.normal,
onToggle: (val) {
setState(() {
v = val;
});
},
)
which looks like this:
That is of course just a sample, you can further customize to get a more beautiful result.
I create custom widget but without cupertinoswitch animation in it. I hope this match your needs =))
GestureDetector(
onTap: () {
setState(() {
val = !val;
});
},
child: Container(
width: size.width * 0.35,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: kSecondaryColor),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Container(
width: 60,
height: 30,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(30),
color: val
? Colors.white
: kSecondaryColor),
child: Center(
child: Text(
'BUY',
style: TextStyle(
fontWeight: FontWeight.bold,
color: val
? Colors.black
: Colors.white),
)),
),
Container(
width: 60,
height: 30,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(30),
color: val
? kSecondaryColor
: Colors.white),
child: Center(
child: Text(
'SELL',
style: TextStyle(
fontWeight: FontWeight.bold,
color: val
? Colors.white
: Colors.black),
)),
),
],
),
),
),
),
add text inside cupertinoswitch flutter
customSwitcher: CupertinoSwitch(
value: model.enableBiometric == 'enable' ? true: false,
activeColor: Color.transparent,
trackColor: Color.transparent,
onChanged: (bool val) {
model.enableBiometric =
(model.enableBiometric == "disable"
? 'enable'
: 'disable');
},),
Container(
width: 70,
height: 36,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular((100)),
border: Border.all(
width: 1.0,
color: model?.enableBiometric == 'enable'
? Color.red
: Color.red,
),
color: Color.red),
child: Row(children: [
if (model?.enableBiometric == "enable")...[
Padding(
padding: EdgeInsets.only(left:model?.enableBiometric == "enable" ? 12 : 0),
child: AppText(
txt:model?.enableBiometric == "enable" ? "Yes" : "",
fontSize: 11,
fontWeight:800,
),
),
] else ...[
SizedBox(
width: 4.0.w,
),
],
Expanded(
child: Container(
// width: ch(12),
//color: AppColor.red,
child: Transform.scale(
transformHitTests: false,
scale: 1.0,
child: customSwitcher!,
),
)),
if (model?.enableBiometric == "disable") ...[
Padding(
padding: EdgeInsets.only(
right:
model?.enableBiometric == "disable" ? 12 : 0),
child: AppText(
txt:
model?.enableBiometric == "disable" ? "No" : "",
fontSize: 11,
fontWeight: 800,
),
),
] else ...[
SizedBox(
width: 4.0.w,
),
]
]),
),
I want to use the result of my DropdownButton to change some text displayed, how would I achieve this?
I have attempted to use a textControlEditor, but I can't make this work with Text.
I want the text to display the advice as the text, which shoiuld be based on value
This is my DropdownButton :
child: Container(
width: 300,
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 15),
decoration: BoxDecoration(
border: Border.all(color: Color(0xff202124), width: 3.0),
color: Colors.white,
borderRadius: BorderRadius.circular(30)),
child: DropdownButton<String>(
onChanged: (value){
setState(() {_selectedColor = value;});
if (value == 'basic') advice = 'Have a great day!';
else if (value == 'Tired') advice = 'Have a rest today!';
else if (value == 'Happy') advice = 'Try to get lots of work done today!';
else if (value == 'Sad') advice = 'Take some time for yourself today';
else if (value == 'Bored') advice = 'Go on a walk and then get back to working';
else if (value == 'Productive') advice = 'Use that productivity';
else advice = 'Good luck today!';
print(advice);
//update text here
},
value: _selectedColor,
underline: Container(),
hint: Center(
child: Text('How have you been feeling today?',
style: TextStyle(color: Color(0xffA9A9A9)),)),
icon: Icon(
Icons.arrow_downward,
color: Color(0xffA9A9A9),
),
isExpanded: true,
items: _emotion
.map((e) => DropdownMenuItem(
child: Container(
alignment: Alignment.centerLeft,
child: Text(
e,
style: TextStyle(fontSize: 18),
),
),
value: e,
)).toList(),
selectedItemBuilder: (BuildContext context) => _emotion
.map((e) => Center(
child: Text(
e,
style: const TextStyle(
fontSize: 18,
color: Color(0xffA9A9A9),
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold),
),
))
.toList(),
),
)),
and here is where I want the text to change:
Expanded(
child: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(20),
width: 300,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: Color(color),
),
child: Center(
child: Text(
advice,
style: TextStyle(fontFamily: 'Arial', fontSize: 18, color: Colors.white, height: 1, ),
textAlign: TextAlign.center,
)
),
),
),
If the whole code is required I am more than happy to share that as well, thank you!
Okay so here you have to create a function which returns String value. This string value will be the value which you select from the drop-down button.
Here's an example:
String getAdvice() {
if (selectedDropDownValue == 'DefaultValue') {
return 'Default Text';
} else {
return '$selectedDropDownValue';
}
}
And then call this function inside the Text Widget where you want the selected advice to appear. Like this:
child: Center:
child: Text(
getAdvice(), //This is the updated line from your code
style: TextStyle(fontFamily: 'Arial', fontSize: 18, color: Colors.white, height: 1, ),
textAlign: TextAlign.center,
),
),
Hope that answers your question. Feel free to clear up any confusions.
I am using DropdownButton and I am facing the following error. When opening the DropdownMenuItem list, I do not have an indent from the button itself. That is, I need to get the padding between the button (DropdownButton) and the dropdown list (DropdownMenuItem) so that there is a distance. But so far I haven't been able to do it. How can you make an indent between them?
code
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
child: DropdownButtonHideUnderline(
child: DropdownButton2(
items: List.generate(
widget.items.length,
(index) => DropdownMenuItem<String>(
value: widget.items[index],
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: StatefulBuilder(
builder: (context, setStateSB) => GFCheckboxListTile(
value: _selectedTitles.contains(widget.items[index]),
onChanged: (bool selected) {
_onItemSelect(selected, index);
setStateSB(() {});
},
selected: selected,
title: Text(
widget.items[index],
style: constants.Styles.smallTextStyleWhite,
),
padding: const EdgeInsets.only(top: 12, bottom: 13),
margin: const EdgeInsets.only(right: 0, left: 0),
size: 22,
activeBgColor: constants.Colors.greyCheckbox,
activeBorderColor: constants.Colors.greyXMiddle,
inactiveBgColor: constants.Colors.greyCheckbox,
activeIcon: SvgPicture.asset(constants.Assets.checkboxIcon),
inactiveBorderColor: constants.Colors.greyXMiddle,
type: type,
),
),
),
),
),
hint: _selectedTitles.length > 1
? const Text('Selecte EV',
style: constants.Styles.bigBookTextStyleWhite)
: Text(_selectedTitles.join().toString(),
style: constants.Styles.bigBookTextStyleWhite),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
itemHeight: 47,
dropdownMaxHeight: 185,
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();
},
),
),
);
}
}
In the dropdown_button2 documentation, there is a property for moving the dropdown menu Offset. You can see it here https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/DropdownButton2/offset.html
On that property you just need to set an Offset, which is composed of an X and Y values.
In your case it would look something like this:
DropdownButton2(
offset: Offset(0,10),
...
),
I am trying to build my own drop down button with separated and condensed menu items, like the image below:
here's the code I have tried so far, I got the drop down width to match the container but the items can't be customized so far and always the height starts from above the button and is not occupying the width of the container:
body: Container(
margin: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
border: Border.all(color: Colors.brown, width: 1.0)),
padding: EdgeInsets.fromLTRB(10.0, 5.0, 10.0, 5.0),
child: DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton(
isExpanded: true,
isDense: true,
value: selection,
icon: Icon(
Icons.arrow_drop_down,
color: Colors.brown,
),
iconSize: 40,
underline: Container(
height: 1,
color: Colors.transparent,
),
onChanged: (String val) => setState(() => selection = val),
items: settingsOptions.map((option) {
return DropdownMenuItem(
value: option,
child: Text(option),
);
}).toList(),
),
),
)
),
),
This is the output from the code:
How do I customize the items width, height and add dividers like in the first image? Thanks
This is an example modify as you like !
DropdownButton(
isExpanded: true,
isDense: true,
value: selection,
icon: Icon(
Icons.arrow_drop_down,
color: Colors.brown,
),
iconSize: 40,
underline: Container(
height: 1,
color: Colors.transparent,
),
onChanged: (String val) => setState(() => selection = val),
items: sampleList.map((option) {
return DropdownMenuItem(
value: option,
child: Container(
width:double.infinity,
alignment:Alignment.centerLeft,
padding: const EdgeInsets.fromLTRB(0,8.0,0,6.0),
child:Text(option),
decoration:BoxDecoration(
border:Border(top:BorderSide(color:Colors.grey,width:1))
)
),
);
}).toList(),
selectedItemBuilder:(con){
return sampleList.map((m){
return Text(m,);
}).toList();
}
)
I came across a flutter Library called dropdown_below in pub.dev. It has additional methods that can allow you customize dropdownMenuItem to your preferred layout.
DropdownBelow(
value: category,
// isDense: true,
itemWidth: MediaQuery.of(context).size.width * 0.92,
itemTextstyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Colors.black),
boxTextstyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Colors.grey.shade600),
boxPadding: EdgeInsets.fromLTRB(13, 12, 0, 12),
boxWidth: MediaQuery.of(context).size.width,
boxHeight: 60,
hint: Text('choose video'),
items: video.data.value.videos
.map((e) => DropdownMenuItem(
onTap: () => e.title,
value: e.title ?? category,
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
e.title ?? '$category',
overflow: TextOverflow.ellipsis,
),
),
),
))
.toList(),
onChanged: (video) {
context.read(videoProvider).cateroryOnChange(video);
},
),
Library Link: https://pub.dev/packages/dropdown_below
The problem with the DropdownButton is that the menu will open randomly based on the selected index and other things. Also, You can't edit its code by just trying to pass offset as the logic code of the paint work based on that and trying to hardcode the selectedItemOffset to a value won't work perfectly fine.
So use DropDownButton2 , which is built just over this .
Package: DropDownButton2
Credits: Ahmed Elsayed
For reference: Refer this link