Flutter: how to set the height of a dropdown in Flutter - flutter

I have a dropdown list in my flutter app that has about 30 items in it. When it is selected I see the values but it takes up whole screen.
How can I control the height of the selected list so that it does not overlay the entire screen (maybe show 10 items with a scroll)
Here is my code
Widget buildCategoryFormField(candidateModel) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Job category"),
SizedBox(
height: 5,
),
FormField(
builder: (FormFieldState state) {
return InputDecorator(
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
),
),
// hintText: "firstname *",
// labelText: "job category",
errorText: state.hasError ? state.errorText : null,
labelStyle: TextStyle(
color: Colors.grey,
),
),
isEmpty: _selectedjobCategory == '',
child: new DropdownButtonHideUnderline(
child: new DropdownButton(
style: TextStyle(fontSize: 18, color: Palette.GREY),
value: _selectedjobCategory,
isDense: true,
onChanged: (String newValue) {
setState(() {
_selectedjobCategory = newValue;
state.didChange(newValue);
});
},
items: JOB_CATEGORY.map((String value) {
return new DropdownMenuItem(
value: value,
child: new Text(value),
);
}).toList(),
),
),
);
},
validator: (val) => validateJobCategory(val),
),
],
);
}

You can define menuMaxHeight on DropdownButton to set maximum height of the expanded dropdown list items.
Expanded(
/// LayoutBuilder can be used to fetch the parent widget's dimensions
child: LayoutBuilder(builder: (context, constraints) {
return Center(
child: DropdownButton<String>(
/// Set dropdown list max height
menuMaxHeight: constraints.maxHeight,
value: dropdownValue,
items: dropdownItems,
),
);
}
)
Adding pagination to the dropdown list is feasible, but this will require creating a custom DropdownButton class. Design-wise, it would be better to break the list into smaller chunks (i.e. by categories) if you'll need to display >50 items in the dropdown.

Related

Show value of dropdown with empty value at the beginning

I would like that in my dropdown at the beginning no value is entered. only if I select the value it should be displayed in the dropdown. if I comment out "value: _selected" is not filled but after the onChanged also nothing is filled.
FormField<Device>(
initialValue: _selected,
builder: (field) {
return InputDecorator(
decoration: InputDecoration(
labelText: widget.labelText,
border: const OutlineInputBorder(),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<Device>(
value: _selected,
isDense: true,
isExpanded: true,
items: widget.list
.map<DropdownMenuItem<Device>>((Device value) {
return DropdownMenuItem<Device>(
value: value,
child:
Text('${value.inventarnr} - ID: ${value.id}'),
);
}).toList(),
onChanged: (value) {
setState(() {
_selected = value;
});
},
),
),
);
},
),
Below worked example for your reference.
initializing default dropdown value
String phaseInitialValue = "Select dropdown";
declare a class to get the user selected value from dropdown.
I have using temporary json data...
List<Phase> phaseList = phaseJsonList.phaseList;
Phase phase = Phase("","");
FormField full code :
FormField(
initialValue: phaseInitialValue,
builder: (field) {
return InputDecorator(
decoration: const InputDecoration(
labelText: "Dropdown",
border: OutlineInputBorder(),
),
child: DropdownButtonHideUnderline(
child: DropdownButton(
hint: Text(
phaseInitialValue,
style: const TextStyle(
fontWeight: FontWeight.w400,
color: Color.fromRGBO(179, 179, 179, 1.0),
fontSize: 15.0,
fontStyle: FontStyle.normal
),
),
isExpanded: true,
iconSize: 30.0,
iconEnabledColor:
const Color.fromRGBO(0, 0, 0, 1.0),
style: const TextStyle(
color: Color.fromRGBO(0, 0, 0, 1)),
dropdownColor:
const Color.fromRGBO(255, 255, 255, 1.0),
borderRadius: BorderRadius.circular(5),
items: phaseList.map(
(phaseData) {
return DropdownMenuItem<Phase>(
value: phaseData,
child: Text(phaseData.phaseName),
);
},
).toList(),
onChanged: (Phase? newData) {
setState(() {
phase = newData!;
phaseInitialValue = newData.phaseName!;
},
);
},
),
),
);
},
),
if user changed the value from dropdown i have retrieve that from onChanged property. there i changed inital text to user selected object...
you can able to fetch actual id as well as object...
have a good day!!!

Hide the bottom line and change the style of the selected element Drowdown_button2

I need your help. I'm using dropdown_button2 from pub.dev but I've run into a few issues that I can't resolve. First mistake: how to change the text style of the selected element? I need the text that displays the selected item to be larger. The second mistake: you need to remove the bottom line, which is displayed under the selected element, when the element is not selected, there is no line, only the element is selected - the line appears. Below I have attached screenshots of what I have now and what I need to get in the end. I would appreciate your help.
dropdown
Widget build(BuildContext context) {
return Container(
width: 120,
decoration: BoxDecoration(
border: Border(
bottom: selectedValue != null
? const BorderSide(
color: constants.Colors.white,
)
: BorderSide.none,
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton2(
hint: const Text(
'Select',
style: constants.Styles.bigBookTextStyleWhite,
),
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,
),
),
if (item == selectedValue)
const Icon(
Icons.check,
color: constants.Colors.purpleMain,
),
],
),
),
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
buttonElevation: 1,
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 Center(
child: Text(
item,
style: constants.Styles.smallTextStyleWhite,
),
);
}).toList();
},
),
),
);
}
at the moment I have
should be the result
To change text style of the selected element use selectedItemBuilder. It's responsible for how the selected item will be displayed on button.
The bottom line under the selected element is shown by the decoration parameter you're using in the main Container widget. Remove it and bottom line should be gone.

Display the label on top of the FormBuilderDropdown with border

I have a FormBuilderDropdown with borders like the below image. But when there is a value in the dropdown, I cannot see the label like in the textbox above the dropdown. I want to show the dropdown with the label with the borders. How it is possible?
Here is the code
FormBuilderDropdown(
name: widget.name,
initialValue: "USA",
decoration: InputDecoration(
labelText: widget.label,
labelStyle: TextStyle(
color: widget.enabled
? Colors.black54
: Theme.of(context).disabledColor),
contentPadding: EdgeInsets.all(16),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Theme.of(context).primaryColor),
),
border: new OutlineInputBorder(borderSide: new BorderSide()),
),
allowClear: widget.allowClear,
hint: Text(widget.hint),
validator: widget.validator,
enabled: widget.enabled,
items: countries
.map((country) => DropdownMenuItem(
value: country['alpha_2_code'],
child: Text(country['en_short_name']),
))
.toList(),
)
In my case, FormBuilderDropdown label is working here.
Do flutter clean and restart the app, it may solve your issue, else check value on items.
Test widget
class _DistrictslayoutState extends State<Districtslayout> {
final districts = List.generate(22, (index) => "item $index");
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FormBuilderDropdown(
name: "name",
initialValue: districts[0],
decoration: InputDecoration(
labelText: "label Text",
labelStyle: TextStyle(
color: true
? Colors.black54
: Theme.of(context).disabledColor),
contentPadding: EdgeInsets.all(16),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Theme.of(context).primaryColor),
),
border: new OutlineInputBorder(
borderSide: new BorderSide()),
),
items: districts
.map(
(e) => DropdownMenuItem(
value: e,
child: Text(e),
),
)
.toList()),
])));
}
}
I am using DropdownButtonFormField which is working pretty well.
DropdownButtonFormField(
// value: 'item1',
hint: Text('select item'),
decoration: InputDecoration(labelText: 'select an item'),
onChanged: (_) {},
dropdownColor: Colors.white,
items: [
DropdownMenuItem(
child: Text('item 1'),
value: 'item1',
),
DropdownMenuItem(
child: Text('item 2'),
value: 'item2',
),
],
),

here my listview is not scrolling dart flutter , please help me iam new to flutter

return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
Positioned(
width: MediaQuery.of(context).size.width,
height: 25.0*SizeConfig.heightMultiplier,
child:Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0xff009cba), Color(0xff000e11)])
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(flex:3,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
FittedBox(child: Text("Firm Details",style: GoogleFonts.lato(color: Color(0xfffbfbfb),fontSize: 1.6*SizeConfig.textMultiplier),/*TextStyle(color: Color(0xfffbfbfb),)*/)),
SizedBox(height: 0.5*SizeConfig.heightMultiplier,),
FittedBox(child: Text("Please select the category that best describes your business model.",style: GoogleFonts.lato(color: Color(0xffb3fbfbfb),fontSize: 1.3*SizeConfig.textMultiplier) /*TextStyle(color: Color(0xffb3fbfbfb),fontSize: 12.0)*/,)),
],
),
),
),
Expanded(flex:1,child:Container(
width: 10.0*SizeConfig.widthMultiplier,
height: 10.0*SizeConfig.heightMultiplier,
child:Image.asset("assets/images/firmDetail.png",width:1.0*SizeConfig.widthMultiplier,height: 1.0*SizeConfig.heightMultiplier,),
), ),
],
),
), ),
Positioned(
top:20.0*SizeConfig.heightMultiplier,
child:Container(
width: MediaQuery.of(context).size.width,
height: 500.0*SizeConfig.heightMultiplier,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0*SizeConfig.widthMultiplier),
color: Colors.white,
),
child:new Container(
child: ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
SizedBox(height: 2.0*SizeConfig.heightMultiplier,),
Center(child: Padding(
padding: EdgeInsets.all(1.8*SizeConfig.heightMultiplier),
child: Text("Please select the category that best describes your business model.",style: GoogleFonts.lato(fontWeight: FontWeight.bold),),
)),
horizontalList1,
verticalList, // here vertical list
],
),
),
),
),
],
),
),
);
here in widget verticallist Listview is not scrolling,but when we add Sizedbox after form with fixedheight then it is scrolling but i dont need fixed height for scrollview
Widget verticalList = new Container(
margin: EdgeInsets.symmetric(vertical: 0*SizeConfig.heightMultiplier),
height: MediaQuery.of(context).size.height,
child:ListView(
shrinkWrap: true,
scrollDirection: Axis.vertical,
children: [
Form(
key: _formKey,
child:ListView(
shrinkWrap: true,
children: [
Padding(
padding:EdgeInsets.only(left:6.0*SizeConfig.widthMultiplier,right: 6.0*SizeConfig.widthMultiplier,top:1.8*SizeConfig.widthMultiplier,bottom: 1.8*SizeConfig.widthMultiplier),
child: new TextFormField(
validator: (String value) {
if (value.isEmpty) {
return 'PinCode';
} else {
return null;
}
},
keyboardType: TextInputType.phone,
controller: _pincode,
// selectionColor:Color(0xffe4065f),
style: GoogleFonts.lato(fontSize: 1.6*SizeConfig.textMultiplier,),
decoration: const InputDecoration(
labelText: "PinCode",
labelStyle: TextStyle(color: Color(0xffe4065f)),
focusColor: Color(0xffe4065f),
hintText:
"PinCode",
hintStyle: TextStyle(fontSize: 13.0),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Color(0xffe4065f))),
),
// style: Theme.of(context).textTheme.body1,
),
),
Padding(
padding:EdgeInsets.only(left:6.0*SizeConfig.widthMultiplier,right: 6.0*SizeConfig.widthMultiplier,top:1.8*SizeConfig.widthMultiplier,bottom: 1.8*SizeConfig.widthMultiplier),
child: new TextFormField(
validator: (String value) {
if (value.isEmpty) {
return 'PAN of the unit. is required';
} else {
return null;
}
},
keyboardType: TextInputType.text,
controller: _pan,
// selectionColor:Color(0xffe4065f),
style: GoogleFonts.lato(fontSize: 1.6*SizeConfig.textMultiplier,),
decoration: const InputDecoration(
labelText: "PAN of the unit",
labelStyle: TextStyle(color: Color(0xffe4065f)),
focusColor: Color(0xffe4065f),
hintText:
"PAN of the unit",
hintStyle: TextStyle(fontSize: 13.0),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Color(0xffe4065f))),
),
// style: Theme.of(context).textTheme.body1,
),
),
Padding(
padding:EdgeInsets.only(left:6.0*SizeConfig.widthMultiplier,right: 6.0*SizeConfig.widthMultiplier,top:1.8*SizeConfig.widthMultiplier,bottom: 1.8*SizeConfig.widthMultiplier),
child: FormField<String>(
builder: (FormFieldState<String> state) {
return InputDecorator(
decoration: InputDecoration(
labelText: "Constitution",
errorStyle: TextStyle(color: Colors.redAccent, fontSize: 1.6*SizeConfig.textMultiplier),
hintText: 'Please select expense',),
isEmpty: _constitutions == '',
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: _constitutions,
isDense: true,
onChanged: (String newValue) {
setState(() {
_constitutions = newValue;
state.didChange(newValue);
});
},
items: _constitution.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value,style: GoogleFonts.lato(fontSize: 1.6*SizeConfig.textMultiplier,)),
);
}).toList(),
),
),
);
},
),
),
Padding(
padding:EdgeInsets.only(left:6.0*SizeConfig.widthMultiplier,right: 6.0*SizeConfig.widthMultiplier,top:1.8*SizeConfig.widthMultiplier,bottom: 1.8*SizeConfig.widthMultiplier),
child: new TextFormField(
validator: (String value) {
if (value.isEmpty) {
return 'Line of Activity is required';
} else {
return null;
}
},
keyboardType: TextInputType.text,
controller: _lineActicity,
// selectionColor:Color(0xffe4065f),
style: GoogleFonts.lato(fontSize: 1.6*SizeConfig.textMultiplier,),
decoration: const InputDecoration(
labelText: "Line of Activity",
labelStyle: TextStyle(color: Color(0xffe4065f)),
focusColor: Color(0xffe4065f),
hintText:
"Line of Activity",
hintStyle: TextStyle(fontSize: 13.0),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Color(0xffe4065f))),
),
// style: Theme.of(context).textTheme.body1,
),
),
Padding(
padding:EdgeInsets.only(
left: 1.0*SizeConfig.widthMultiplier,
right: 1.0*SizeConfig.widthMultiplier,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FlatButton(
onPressed: () {
//x _postData();
if (!_formKey.currentState.validate()) {
//_formKey.currentState.save();
if (_constitutions == null || _districtSelectedValue == null) {
print("eroore");
Flushbar(
message: "please select required fields",
duration: Duration(seconds: 3),
)..show(context);
} else {
// Every of the data in the form are valid at this point
_formKey.currentState.save();
print(_constitutions);
}
} else {
// submitOtp();
_postData();
}
},
child: Text(
"SAVE & NEXT",
style: GoogleFonts.lato(color: Colors.white),
),
color: Color(0xffe4065f),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
side: BorderSide(color: Color(0xffe4065f)),
),
),
],
),
),
],
),
),
// SizedBox(height: 1000,),
],
)
);
here ,when we add Sizedbox after form with fixedheight then it is scrolling but i dont need fixed height for scrollview im new to flutter please help
You can wrap your main widget with the SingleChildScrollView widget
I would suggest a simple widget hierarchy like
Scaffold
- Container (For the red background)
- Column
- Container (with size for the lorem ipsom text.
- Lorem Ipso Text.
- Expanded (So that it will use the rest of the height automatically.)
- Container (with white back ground and top rounded borders. Makes sure you add circular borders only to top and not to bottom of this container.
- DefaultTabController
- builder (to get different context of the default tab controller if more than one is used in your full app.)
- Column
- TabBar (if the number of categories is large use scrolling here as a property of the tab bar.) wrap in container if you need specific height of the tab bar.
- Expanded
- TabBarView to show the appropriate form.
- SingleChildScrollView
-Column
-Your fields
your list view is wrapper in a container that is very long and has no scroll on it. So it wont scroll as the list fits within that long container.
With list views you want a fixed height. It is the fixed height that is given for the visible parts of the list. Remove the wrapping container or reduce the height so all of it is visible on screen.
Also look at your use of the stack. You might have issues once you fix this with the list scrolling on top of the text "Firm Details" etc.

How to force flutter to rebuild a specific widget when setState is called

I have a stateful widget class. It has a listView in its build method. Inside the list view I have two dropDownButtonFormField. Initially, only the first drop down is shown. After a value is selected in to, the second drop down is drawn by calling the set state. The second drop down button is dependent on the first button's choice.
Now the code works fine. After selecting the value in the first drop down button, the second drop down button appears with options corresponding to the first's selected value. But error occurs when a an option from the second button is selected and first button's option is changed.
How do I force flutter to redraw the second dropdown every time the first drop down's selected option is changed?
Here is the app running and crashing:
Code:
//called inside the list view childrens list
Widget showLocationDropDown() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
child: Container(
child: Column(
children: <Widget>[
_getProvinceDropDown(),
_selectedProvince == null ? Container(): _getCityDropDown(),
],
),
),
);
}
Widget _getCityDropDown() {
return Column(
children: <Widget>[
Container(
height: 20,
),
Row(
children: <Widget>[
Icon(Icons.location_city, color: Colors.grey),
Container(
width: 17.0,
),
Expanded(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButtonFormField(
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(color: Colors.grey))),
hint: Text('Please choose your city'),
value: _selectedCity,
onChanged: (newValue) {
setState(() {
_selectedCity = newValue;
});
},
items: _getCities().map((location) {
return DropdownMenuItem(
child: Text(location),
value: location,
);
}).toList(),
),
),
),
],
),
],
);
}
List<String> _getCities() {
switch (_selectedProvince) {
case ("Sindh"):
return _sindhCities;
case ("Punjab"):
return _punjabCities;
case ("Balouchistan"):
return _balouchCities;
case ("KPK"):
return _kpkCities;
}
List<String> deflt = ['Please Select Province'];
return deflt;
}
Widget _getProvinceDropDown() {
return Row(
children: <Widget>[
Icon(Icons.map, color: Colors.grey),
Container(
width: 17.0,
),
Expanded(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButtonFormField(
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(color: Colors.grey),
),
),
hint: Text('Please choose your province'),
value: _selectedProvince,
onChanged: (newValue) {
setState(() {
_selectedProvince = newValue;
_selectedCity = null;
stateChange = !stateChange;
});
},
items: _province.map((province) {
return DropdownMenuItem(
child: Text(province),
value: province,
);
}).toList(),
),
),
),
],
);
}
Instead of _selectedCity = null, try _selectedCity = _getCities().first;
running $ flutter upgrade worked.