I’m trying to implement a dropdown in my Flutter app such that when it opens, if the selected item is not visible, it automatically scrolls to make the item visible. However, I haven’t been successful so far. Could someone please help me with this?
What I’ve Tried So Far:
Using ScrollController: I attempted to attach a ScrollController to the dropdown’s list view and call animateTo to scroll to the selected item, but the scroll action didn’t work as expected.
Programmatically Scrolling: Tried programmatically scrolling using various methods such as ScrollController.jumpTo and ScrollController.animateTo, but I couldn’t get the item to be visible when the dropdown opens.
Adding Delay: Added delays using Future.delayed before attempting to scroll, thinking the list might not be fully rendered yet, but still no success.
@override
Widget build(BuildContext context) {
if (widget.isLoading) {
return Center(child: CircularProgressIndicator());
}
return DropdownSearch<String>(
key: dropdownSearchKey,
enabled: widget.isEnabled,
items: widget.isEnabled ? itemLabels : [],
selectedItem: selectedItem.isEmpty || !widget.isEnabled ? widget.hint : selectedItem,
compareFn: (left, right) => left == right,
onChanged: (selectedItem) {
setState(() {
this.selectedItem = selectedItem ?? '';
});
String? key = reverseMap[selectedItem ?? ''];
if (key != null) {
widget.onChanged({'key': key, 'value': selectedItem ?? ''});
} else {
widget.onChanged({'key': '', 'value': ''});
}
},
dropdownButtonProps: DropdownButtonProps(
icon: Transform.scale(
scale: 1.6,
child: Icon(
Icons.arrow_drop_down,
color: widget.isEnabled ? Theme.of(context).primary : Colors.grey, //icon
),
),
),
popupProps: PopupProps.dialog(
// scrollbarProps: ,
showSelectedItems: true,
showSearchBox: widget.isEnabled,
//+++++++++++++++++++++++++++++++++++++
searchFieldProps: TextFieldProps(
controller: editTextController,
decoration: InputDecoration(
labelText: 'Search',
labelStyle: Theme.of(context).textTheme.headlineSmall!.copyWith(
letterSpacing: 0.0,
fontSize: 16.0,
color: widget.isEnabled ? Theme.of(context).lightCoral : Colors.grey,
fontWeight: FontWeight.w500,
),
contentPadding: EdgeInsets.only(left: 8),
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () {
if (editTextController.text.isEmpty) {
dropdownSearchKey.currentState?.closeDropDownSearch();
editTextController.clear();
_clearSelection();
widget.onClear();
} else {
editTextController.clear();
}
},
),
),
),
//+++++++++++++++++++++++++++++++++++++
dialogProps: DialogProps(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
backgroundColor: Colors.white,
),
itemBuilder: (context, item, isSelected) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), //selecao
decoration: BoxDecoration(
color: isSelected ? Theme.of(context).secondary : Colors.transparent,
),
child: Text(
item,
style: Theme.of(context).textTheme.headlineSmall!.copyWith(
letterSpacing: 0.1,
fontSize: 18.0,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
// color: Theme.of(context).primary,
color: isSelected ? Colors.white : Theme.of(context).primary,
),
),
);
},
onDismissed: () {
editTextController.clear();
},
containerBuilder: (context, popupWidget) {
return Column(
children: [
Expanded(child: popupWidget),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
textStyle: TextStyle(
fontSize: 18,
),
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
onPressed: () {
dropdownSearchKey.currentState?.closeDropDownSearch();
editTextController.clear();
_clearSelection();
widget.onClear();
},
child: Text("Cancel"),
),
),
],
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
filled: true,
fillColor: Colors.white,
labelStyle: TextStyle(
color: widget.isEnabled ? Theme.of(context).primary : Colors.grey,
),
),
baseStyle: Theme.of(context).textTheme.headlineSmall!.copyWith(
letterSpacing: 0.0,
fontSize: 16.0,
color: widget.isEnabled ? Theme.of(context).primary : Colors.grey,
),
),
);
}