当执行“DropdownButtonFormField”小部件的构建方法时,如果用户已经单击它并且在 UI 中显示了选项,那么构建方法似乎不会更新这些选项。我尝试了各种方法并询问了 AI 无济于事; :-(
目前,小部件是
//...
import 'package:get_it/get_it.dart';
//...
class DynamicDropdown extends StatefulWidget {
final void Function(ClientLItem) onSelected;
const DynamicDropdown(
{super.key,
/*required Key key,*/ required this.onSelected}) /*: super(key: key)*/;
@override
_DynamicDropdownState createState() => _DynamicDropdownState();
}
class _DynamicDropdownState extends State<DynamicDropdown> {
String name = '_DynamicDropdownState';
ClientLItem? _selectedClient;
String dropdownValue = "0";
bool shouldUpdate = false;
ClientListicle _clientListicle = GetIt.I.get<ClientListicle>();
List<DropdownMenuItem<String>> menuItems = [
const DropdownMenuItem(value: "0", child: Text('Select')),
];
final _dropdownKey = GlobalKey<FormFieldState>();
List<DropdownMenuItem<String>>? get dropdownItems {
developer.log(
'get dropdownItems() clients have ${_clientListicle.items.length} clients',
name: name);
List<DropdownMenuItem<String>> newItems = [
const DropdownMenuItem(value: "0", child: Text('Select')),
];
for (var element in _clientListicle.items) {
DropdownMenuItem<String> potentialItem = DropdownMenuItem(
value: element.id.toString(), child: Text(element.title));
newItems.add(potentialItem);
developer.log('menu items count ${newItems.length}', name: name);
}
developer.log('new menu items count ${newItems.length}', name: name);
if (newItems.length <= 1) {
return null;
} else {
//if length of newitems differs from menu items schedule a forced rebuild
if (newItems.length != menuItems.length) {
menuItems = newItems;
shouldUpdate = true;
_onClientListicleUpdated();
_dropdownKey.currentState!.build(context);
}
return menuItems;
}
}
@override
void initState() {
developer.log('initState', name: name);
super.initState();
// Listen for changes in the ClientListicle instance
_clientListicle.addListener(_onClientListicleUpdated);
// if _clientListicle.items.isEmpty load some clients
WidgetsBinding.instance.addPostFrameCallback((_) async {
developer.log('addPostFrameCallback', name: name);
if (_clientListicle.items.isEmpty) {
fetchClients();
}
if (shouldUpdate) {
shouldUpdate = false;
setState(() {
// update state here
});
_dropdownKey.currentState!.reset();
}
});
}
@override
void dispose() {
// Remove the listener when the widget is disposed
_clientListicle.removeListener(_onClientListicleUpdated);
super.dispose();
}
void _onClientListicleUpdated() {
developer.log('_onClientListicleUpdated');
// Call setState to rebuild the widget when the ClientListicle instance is updated
setState(() {
dropdownItems;
});
_dropdownKey.currentState!.reset();
}
@override
State<StatefulWidget> createState() {
developer.log('createState()');
return _DynamicDropdownState();
}
@override
Widget build(BuildContext context) {
developer.log(
'Build ClientListicle has ${_clientListicle.items.length} items',
name: name);
developer.log('dropdownItems has ${dropdownItems?.length} items',
name: name);
if (shouldUpdate) {
developer.log('shouldUpdate is true', name: name);
shouldUpdate = false;
// Schedule a rebuild
setState(() {});
}
return DropdownButtonFormField<String>(
key: _dropdownKey,
value: dropdownValue,
icon: const Icon(Icons.keyboard_arrow_down),
items: dropdownItems,
validator: (value) => value == "0" ? 'Please select a client' : null,
onChanged: (String? newValue) {
if (newValue != null && newValue != "0") {
developer.log('selected newValue $newValue', name: name);
dropdownValue = newValue;
_selectedClient =
_clientListicle.getById(int.parse(newValue!)) as ClientLItem;
setState(() {});
widget.onSelected(_selectedClient!);
} else {
_selectedClient = null;
dropdownValue = "0";
}
_dropdownKey.currentState!.reset();
},
);
}
Future<void> fetchClients() async {
developer.log('fetchClients', name: name);
await _clientListicle.fetch(numberToFetch: 5);
}
}
根据日志输出,我可以看到例如
[_DynamicDropdownState] Build ClientListicle has 3 items
,但在数据到达之前单击下拉列表时,仍然只能看到可用的单个项目。
如果我在下拉菜单外单击并重新打开它,则会出现正确的项目,因此有状态小部件内的 setState 似乎不会强制重建 UI 中的选项列表。
你没有明确说明你的问题。是否有两个下拉字段,一个用于客户,另一个用于客户特定选项?
您可以尝试创建一个 StatefullWidget 并将下拉菜单放在那里,然后通过调用它的 setState 您应该能够更新下拉菜单项