How to make DropdownButton menu width to fit text? - flutter

I want to have a dropdown button that has a width based on the menu text length. The dropdown arrow does not have any additional spacing between text.
Like this:
Currently, I am getting this:
My dropdown button arrow is positioned based on the longest text.
My code:
Widget dropdownList(){
return Container(
child: DropdownButton<Location>(
value: _selectedValue,
icon: const Icon(Icons.expand_more),
iconSize: 30,
underline: SizedBox(),
onChanged: (Location? newValue) {
setState(() {
_selectedValue = newValue!;
});
},
style: const TextStyle(color: Colors.blue),
selectedItemBuilder: (BuildContext context) {
return locationList.map((Location value) {
return Container(
child: Text(
value.name,
style: const TextStyle(color: Colors.black,fontSize: 30,
fontWeight: FontWeight.w300),
),
);
}).toList();
},
items: locationList.map<DropdownMenuItem<Location>>((Location value) {
return DropdownMenuItem<Location>(
value: value,
child: Text(value.name, style: TextStyle(color: Colors.black,fontSize: 15,
fontWeight: FontWeight.w300)),
);
}).toList(),
),
);
}

According to the documentations there is a property for DropDownButton called isExpanded:
isExpanded → bool
Set the dropdown's inner contents to horizontally fill its parent. [...]
final
so just set:
isExpanded = true;

Related

How to control text overflow in Flutter when using a Text widget in a dropdown?

I'm using the next piece of code to render an item for a Dropdown component on Flutter web:
Widget _getColorInfo(int color, String text) {
return Row(
children: [
Container(
width: 10,
height: 10,
decoration: BoxDecoration(
color: Color(color),
borderRadius: BorderRadius.circular(5),
),
),
const SizedBox(width: 5),
Text(
text,
style: TextStyle(
color: Color(color),
overflow: TextOverflow.ellipsis,
fontWeight: FontWeight.bold,
fontSize: ShapeStyle.standardFontSize,
),
),
],
);
}
Now the problem is that if I do not use Flex or Expanded the widget will not recognize the overflow:
Overflow on the selected item
And the dropdown is working:
Overflow on the expanded panel
Now, if I use Flex the overflow is now recognized by the main component:
Flexible(
child: Text(
text,
style: TextStyle(
color: Color(color),
overflow: TextOverflow.ellipsis,
fontWeight: FontWeight.bold,
fontSize: ShapeStyle.standardFontSize,
),
),
),
Overlfow handled on the selected item
But now the dropdown is not working since it detects the 'size' property is missing:
Error on the expanded panel of the dropdown
Here is the error:
Image of the error
The problem is that I can't use the size of the screen to determine how much width is the component taking since all the other components are being expanded dynamically, so it will break the UI symmetry. Is there any other way to control the overflow when using a dropdown or something to differentiate the dropdown panel from the selected item so I can apply different strategies like using a fixed width for the dropdown panel and a Flex for the selected item?
I have already tried using Flex, Expanded, try catch, Wrap, ConstrainedBox, third party packages... nothing solved the problem.
UPDATE
Here is the full code of the component:
class ColorSelect extends StatelessWidget {
final AgendaFormHandler form;
final int? defaultColor;
final Map<String, int> elements = {
'Team 1': 0xFFFEC000,
'Team 2': 0xFF65CBFD,
'Team 3': 0xFFF2B085,
'Team 4': 0xFF01AE51,
'USO': 0xFF3764F7,
'Financiero': 0xFF702FA0,
'Procesos': 0xFF8FA9DA,
'TI': 0xFFFF7C81,
'Alterno 1': 0xFF00F3EB,
'Alterno 2': 0xFFA46B6B,
'Alterno 3': 0xFFDCBFB2,
'Alterno 4': 0xFFEF5CEF,
'Alterno 5': 0xFFC5D89F,
};
ColorSelect({super.key, required this.form, this.defaultColor});
#override
Widget build(BuildContext context) {
return SimpleSelectInput<int>(
title: 'Color',
customEmptyText: 'Ninguno',
activeOption: form.getValue<int?>('color') ?? defaultColor ?? 0xFFFEC000,
onOptionSelected: (color) {
form.updateValue('color', color);
},
options: List<SelectItem<int>>.from(elements.keys.map((key) {
return SelectItem(
value: elements[key]!,
text: key,
label: _getColorInfo(elements[key]!, key),
);
})),
);
}
Widget _getColorInfo(int color, String text) {
return Row(
children: [
Container(
width: 10,
height: 10,
decoration: BoxDecoration(
color: Color(color),
borderRadius: BorderRadius.circular(5),
),
),
const SizedBox(width: 5),
Flexible(
fit: FlexFit.tight,
child: Text(
text,
style: TextStyle(
color: Color(color),
overflow: TextOverflow.ellipsis,
fontWeight: FontWeight.bold,
fontSize: ShapeStyle.standardFontSize,
),
),
),
],
);
}
}
Here is the code of the SimpleSelectInput
/// A class to create a new option entry for the [SimpleSelectInput]
/// component with [T] as the datatype for the [value] and [String]
/// for the [label]
class SelectItem<T> {
final T value;
/// This text is only to be able to compare the content of the
/// input when applying any search filter. So, the same you put
/// in the [label] property is the one you should put here.
final String text;
final Widget? label;
SelectItem({
required this.value,
this.label,
required this.text,
});
}
/// A simple input with a bottom border and a blue title with
/// [T] as the value datatype for the dropdown options.
class SimpleSelectInput<T> extends StatelessWidget {
/// The options to be displayed in the dropdown
final List<SelectItem<T>> options;
/// The item to be rendered as the default selected item
final T activeOption;
final Function(T?) onOptionSelected;
final String Function(T?)? validator;
final String? title;
/// The text to be displayed when no option is selected
final String? customEmptyText;
final bool shouldDecorate;
final bool showSearchBox;
const SimpleSelectInput({
super.key,
required this.options,
required this.activeOption,
required this.onOptionSelected,
this.title,
this.validator,
this.shouldDecorate = true,
this.showSearchBox = false,
this.customEmptyText = '-- Seleccione --',
});
#override
Widget build(BuildContext context) {
if (activeOption == null) {
return Container();
}
// If there is no opportunity it will raise an error.
// TODO: check if it's ok to raise the BadState error.
late final SelectItem<T>? selectedOption;
try {
selectedOption = options.firstWhere(
(SelectItem<T> option) {
return option.value == activeOption;
},
);
} catch (_) {
selectedOption = null;
}
return DropdownSearch<SelectItem<T>>(
items: options,
selectedItem: selectedOption,
filterFn: (item, filter) {
return item.text.toLowerCase().contains(filter.toLowerCase());
},
dropdownButtonProps: const DropdownButtonProps(
focusColor: ColorStyle.blue,
color: Colors.black,
icon: Icon(
Icons.arrow_drop_down,
size: ShapeStyle.standardFontSize * 1.4,
),
),
dropdownBuilder: (context, value) {
return value?.label ??
Text(
customEmptyText ?? '-- Seleccione --',
style: const TextStyle(
fontSize: ShapeStyle.standardFontSize,
),
);
},
validator: (selected) {
return validator?.call(selected?.value);
},
popupProps: PopupPropsMultiSelection.menu(
showSearchBox: showSearchBox,
showSelectedItems: true,
itemBuilder: _itemBuilder,
searchFieldProps: const TextFieldProps(
scrollPadding: EdgeInsets.zero,
style: TextStyle(
color: ColorStyle.blue,
fontSize: ShapeStyle.standardFontSize,
),
),
),
compareFn: (i, s) => i.value == s.value,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
fillColor: Colors.black,
border: shouldDecorate ? null : InputBorder.none,
labelStyle: const TextStyle(
color: ColorStyle.blue,
fontSize: ShapeStyle.standardFontSize * 1.4,
),
label: title != null
? Text(
title!,
style: const TextStyle(
fontSize: ShapeStyle.standardFontSize * 1.4,
),
)
: null,
),
),
onChanged: (x) => onOptionSelected(x?.value),
);
}
Widget _itemBuilder(
BuildContext context, SelectItem<T> item, bool isSelected) {
final size = MediaQuery.of(context).size;
return Container(
width: size.width,
padding: const EdgeInsets.symmetric(
vertical: 12.0,
horizontal: 8.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
item.label ??
Text(
item.text,
style: const TextStyle(
color: Colors.black,
fontSize: ShapeStyle.standardFontSize,
),
),
// a check icon
if (isSelected)
const Icon(
Icons.check,
color: Colors.green,
size: ShapeStyle.standardIconSize,
),
],
),
);
}
}

Flutter Dropdown list expanding instead of scrolling

So im making my first Dropdown but when i have a lot of Strings it expands upwards, is there a way to compact the list and make it scrollable or am i using the wrong Widget?
class _DropdownBehaivorButton extends StatefulWidget {
const _DropdownBehaivorButton({super.key});
#override
State<_DropdownBehaivorButton> createState() => _DropdownBehaivorButtonState();
}
class _DropdownBehaivorButtonState extends State<_DropdownBehaivorButton> {
String dropdownvalue = 'Agresivo';
var tipos = [
'Agresivo',
'Tranquilo',
'Travieso',
'Docil',
'Travieso',
'Travieso',
'Travieso'
];
#override
Widget build(BuildContext context) {
return
DropdownButtonHideUnderline(
child: DropdownButton(
borderRadius: BorderRadius.circular(25),
isExpanded: true,
iconEnabledColor: Color(0xff525252),
dropdownColor: Colors.white,
style: _textStyle(),
value: dropdownvalue,
icon: const Icon(Icons.keyboard_arrow_down),
items: tipos.map((String items) {
return DropdownMenuItem(
value: items,
child: Center(child: Text(items)),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
dropdownvalue = newValue!;
});
},
),
);
}
TextStyle _textStyle() => TextStyle(
fontSize: 18,color: Color.fromARGB(123, 82, 82, 82),fontWeight: FontWeight.w400) ;}
I was expecting a compact dropdown list like this
DropdownButton(
menuMaxHeight: 100, // this line
hint: const Text(
"Please select Child / Patient"),
underline: const SizedBox(),
isExpanded: true,
iconEnabledColor: Colors.blue[800],
dropdownColor: Colors.grey[100],
style: TextStyle(
letterSpacing: 2,
fontWeight: FontWeight.bold,
fontSize: 12,
color: Colors.grey[800]),
value: patientName,
items: patients.map((patient) {
return DropdownMenuItem(
value: patient,
child: Text(patient.childName),
);
}).toList(),
onChanged: (value) {
setState(() {
patientName = value;
debugPrint(patientName!
.toJson()
.toString());
});
}),
try changing the menu max height
Try to add dropdownMaxHeight: 200
Here you will find what you need https://pub.dev/packages/dropdown_button2

Dropdownbutton restrict shown items

Ive got the following Problem:
I want the user to choose a day of month with a dropdownbutton. So my items are the numbers 1 to 31. Now the list got pretty long and the Dropdownbutton is really large. Is there a Solution to show e.g. only 5 Elements at the same time?
Widget buildDropdownMonthlyTurnus() {
return DropdownButton<int>(
value: _selectedDay,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: TextStyle(color: Colors.blue),
underline: Container(
height: 2,
color: Colors.blue,
),
onChanged: (int newValue) {
setState(() {
_selectedDay = newValue;
});
},
items: Constants.daysOfMonth.map((int value) {
return new DropdownMenuItem<int>(
value: value,
child: new Text(
value.toString(),
style: new TextStyle(color: Colors.black),
),
);
}).toList());
}
In the link you see my problem with the large list.
enter image description here
For this problem you can use listview, inside a container and show manage its size according to the list items shown, you don't need to use dropdown items at all.
Use the menuMaxHeight property of the DropdownButton class. It's a recent addition to control the height of the menu.
Widget buildDropdownMonthlyTurnus() {
return DropdownButton<int>(
menuMaxHeight: 200.0,
value: _selectedDay,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: TextStyle(color: Colors.blue),
underline: Container(
height: 2,
color: Colors.blue,
),
onChanged: (int newValue) {
setState(() {
_selectedDay = newValue;
});
},
items: Constants.daysOfMonth.map((int value) {
return new DropdownMenuItem<int>(
value: value,
child: new Text(
value.toString(),
style: new TextStyle(color: Colors.black),
),
);
}).toList());

How to change height of DropdownButton in flutter

How can I change the height of a DropdownButton in flutter.
I have tried to use Padding and SizedBox but none is realy working.
SizedBox just increases the container size while the DropdownButton is clamped to top left and therefore is not centered anymore.
Padding is ignored or moves the content outside of the button.
I do not want to change the size of the dropdown overlay but the button itself.
build(BuildContext context) {
return ThemeData(
data: ThemeData(canvasColor: Colors.white),
child: DropdownButton(
items: _items.map((item) => DropdownMenuItem(child: Text(item), value: item)).toList(),
isExpanded: true,
selectedItemBuilder: (_) {
return _items.map<Widget>((String lang) {
return Center(
widthFactor: 1,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text(lang, style: TextStyle(color: Colors.black))
),
);
}).toList();
}
)
)
}
Wrap it in a Container, give a height, width as per your need and set isExpanded true in DropDownButton. Also change dropdownbutton text font size as per your need.
Container(
height: 50.0,
width: 200.0,
child: DropdownButton(
value: dropdownValue,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
isExpanded: true,
style: TextStyle(color: Colors.deepPurple, fontSize: 20.0),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)
)
End product should look something like this,
Looks like the 'itemHeight' property for the DropdownButton class should do the trick. I tried it and it increased the height of my DropdownButton.
Here is some sample code I have from a previous project using the itemHeight:
DropdownButton<String>(
itemHeight: 100.0,
value: selectedCurrency,
items: dropdownItems,
onChanged: (value) {
setState(() {
selectedCurrency = value;
getData();
});
},
);
Note: Just make sure the value you provide isn't less than 48.0, since it will give an error.
Docs:
itemHeight property: https://api.flutter.dev/flutter/material/DropdownButton/itemHeight.html
Minimum itemHeight defined by 'kMinInteractiveDimension':
https://api.flutter.dev/flutter/material/kMinInteractiveDimension-constant.html
itemHeight: null,
You just need to leave the itemHeight with the null value.
It will make the height of the DropdownButton with the menu item's intrinsic height.
Use SizedBox Widget
SizedBox(
height: 30,
child:DropdownButton<String>(
value: selectedCurrency,
items: dropdownItems,
onChanged: (value) {},
))
The easiest of all methods is using DropDownButton2 which is built over DropDownButton
And just change the buttonHeight attribute
Not just buttonHeight , you can even change itemHeight , buttonwidth and many more customize
String? selectedValue;
List<String> items = [
'Item1',
'Item2',
'Item3',
'Item4',
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButtonHideUnderline(
child: DropdownButton2(,
items: items
.map((item) =>
DropdownMenuItem<String>(
value: item,
child: Text(
item,
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
setState(() {
});
},
buttonHeight: 40,
buttonWidth: 140,
itemHeight: 40,
),
),
),
);
}
checkout : DropDownButton2 for more examples.
Hope it helps !!
You need to use menuMaxHeight property of DropdownButton Widget.
child: DropdownButton(
menuMaxHeight: 500.0,
value: '1',
items: setTotalPages(),
onChanged: (String? newValue) {
setState(() {
dropdownvalue = newValue!;
});
},
)
Add this property menuMaxHeight: 200, to DropdownButton

How to open dropDownButton from RaisedButton

Using Flutter.
When a user taps a button, I want focus to shift to a dropDownButton and open up the options. Here is my attempt (not working):
RaisedButton(
onPressed: () {setState(() {FocusScope.of(context).requestFocus(_node);exactTime = false;});},
color: Theme.of(context).primaryColor,
child: const Text(
'Estimate',
style: TextStyle(fontSize: 20)
),
)
DropdownButton<String>(
isExpanded: true,
focusNode: _node,
items: ageRanges.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
);
}).toList(),
value: pmhOnset,
onChanged: (String selected) {
setState(() {
pmhOnset = selected;
});
},
)
I don't get any errors. It just doesn't do anything. Any suggestions?
From what I have read it is not possible with out making your own DropDownButton class but that shouldn't be that hard after all just a matter of coping most of flutters code and changing it to fit your need I'll attach a link that I think you will find helpful.