I need a custom dropdown that when opened shows an image in a column, and in the second column three lines of text. When an item is selected, the image and only the first row of text should be visible.
The three lines of text is dynamic and can be long, so I need to handle overflowing.
I cannot get it to work. This is how it currently looks.
Opened:
Closed:
As one can see, the opened state has overflow problems. The closed state has overflow problems and the other two lines are shown.
This is the current component code:
class BDImageDropdownButton extends StatelessWidget {
final bool disabled;
final String? labelText;
final IconData? icon;
final String? Function(dynamic)? validator;
final FormFieldSetter<dynamic>? onSaved;
final List<DropdownMenuItem<dynamic>> items;
final dynamic value;
final void Function(dynamic value)? onChanged;
const BDImageDropdownButton({required this.labelText, this.icon, this.disabled = false, this.onChanged, this.validator, this.onSaved, required this.items, this.value, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
items.add(
DropdownMenuItem(
value: 1,
child: SizedBox(
height: 100.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Image.asset('assets/radiatorTypes/testImage.png'),
Padding(
padding: const EdgeInsets.only(left: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium',
style: Theme.of(context).textTheme.headline6?.copyWith(fontWeight: FontWeight.bold),
overflow: TextOverflow.fade,
softWrap: false,
),
SizedBox(height: 5),
Text(
'odit aut fugit, sed quia consequuntur magni dolores eos qui ratione',
overflow: TextOverflow.fade,
softWrap: false,
),
SizedBox(height: 5),
Text('iquid ex ea commodi consequatur? Quis autem vel eum'),
],
),
)
],
),
),
),
);
return DropdownButtonFormField<dynamic>(
validator: validator,
decoration: InputDecoration(
filled: true,
prefixIcon: icon != null ? Icon(icon) : null,
labelText: labelText,
labelStyle: TextStyle(color: disabled ? Colors.grey : Color(0xFFAFAFAF)),
contentPadding: EdgeInsets.only(left: 12, top: 9, bottom: 6, right: 12),
errorBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Color(0xffba0000),
width: 3,
),
),
),
items: disabled ? [] : items,
onChanged: (value) => {
if (onChanged != null) {onChanged!(value)}
},
onSaved: onSaved,
value: value,
);
}
}
I´ve googled alot, and tried many different things (isExpanded, itemHeight etc.), but nothing seems to fit this situation.
Regarding the need for only showing the first line I could work it out with some variable that keeps track of open/closed state and then use it for showing/hiding the other two lines. But I guess there is a cleaner solution for this?
Thanks!
2
Answers
After fiddling around with Rows, columns, flexibles and containers for some time, I found this solution.
This allows text overflow in multiple columns in the dropdown when its opened. When the dropdown is closed I use the selectedItemBuilder to create a "custom" representation of the selected Item. The only problem here is that I have to set a width on the container of the row (
MediaQuery.of(context).size.width * 0.85
) - else I get constrain errors because of the row. I have not managed to find another solution to this unfortunately - so suggestions to this problem is very welcome!(In the screenshots I have two items in the list, but not in the code sample for the sake of saving space)
Code: (static code and values, shall of course be dynamic)
To solve overflowing text problem you need to use
SingleChildScrollView
, to fit two widgets horizontally within the screen space inside aRow
, you need to wrap the row’s children withExpanded
widgets, this is full example (change the values of the flex parameter as you see fit), and I used your code in the example, just made few changes to the values of the text widgets, you can copy it again and put it inside any other widget (in your case put it in the drop down button):