Flutter:如何在前一个DropDownFormField选中数据后创建关联的DropDownFormField
Cascading DropDownFormField Example in Flutter
Hey there! I’ve built exactly this kind of cascading dropdown functionality before—here’s a straightforward, working example that you can adapt for your use case.
Core Idea
We’ll use a StatefulWidget to track two pieces of state:
- The selected main option (House/Hotel/Apartment)
- The selected sub-option (depends on the main choice)
We’ll also define a map that links each main option to its corresponding sub-options.
Complete Code
import 'package:flutter/material.dart'; class CascadingDropdowns extends StatefulWidget { const CascadingDropdowns({super.key}); @override State<CascadingDropdowns> createState() => _CascadingDropdownsState(); } class _CascadingDropdownsState extends State<CascadingDropdowns> { // Track selected values String? _selectedMainOption; String? _selectedSubOption; // Map main options to their sub-options final Map<String, List<String>> _subOptionMap = { 'House': ['Room', 'Kitchen'], 'Hotel': ['Single Room', 'Double Room'], 'Apartment': ['Bedroom', 'Living Room', 'Balcony'], // Added for completeness }; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Cascading Dropdowns')), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // First DropdownFormField DropdownFormField<String>( decoration: const InputDecoration( labelText: 'Select Property Type', border: OutlineInputBorder(), ), value: _selectedMainOption, items: _subOptionMap.keys.map((option) { return DropdownMenuItem( value: option, child: Text(option), ); }).toList(), onChanged: (newValue) { setState(() { _selectedMainOption = newValue; // Reset sub-option when main option changes _selectedSubOption = null; }); }, validator: (value) { if (value == null) { return 'Please select a property type'; } return null; }, ), const SizedBox(height: 20), // Second DropdownFormField (only shows if main option is selected) if (_selectedMainOption != null) DropdownFormField<String>( decoration: InputDecoration( labelText: 'Select ${_selectedMainOption} Area', border: const OutlineInputBorder(), ), value: _selectedSubOption, items: _subOptionMap[_selectedMainOption]!.map((subOption) { return DropdownMenuItem( value: subOption, child: Text(subOption), ); }).toList(), onChanged: (newValue) { setState(() { _selectedSubOption = newValue; }); }, validator: (value) { if (value == null) { return 'Please select an area'; } return null; }, ), const SizedBox(height: 20), // Optional: Button to show selected values ElevatedButton( onPressed: () { if (Form.of(context)?.validate() ?? false) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Selected: $_selectedMainOption > $_selectedSubOption', ), ), ); } }, child: const Text('Submit'), ), ], ), ), ); } } // Helper widget (convenience wrapper for Dropdown + FormField) class DropdownFormField<T> extends FormField<T> { DropdownFormField({ super.key, super.validator, required List<DropdownMenuItem<T>> items, T? value, required void Function(T?) onChanged, required InputDecoration decoration, }) : super( initialValue: value, builder: (FormFieldState<T> state) { return InputDecorator( decoration: decoration.copyWith( errorText: state.errorText, ), child: DropdownButtonHideUnderline( child: DropdownButton<T>( value: state.value, isExpanded: true, items: items, onChanged: (newValue) { state.didChange(newValue); onChanged(newValue); }, ), ), ); }, ); } // To run this, add it to your MaterialApp home: // home: const CascadingDropdowns(),
Key Details Explained
- State Management: We use
setStateto update the UI whenever selected options change—this ensures the second dropdown updates immediately when the first choice is modified. - Resetting Sub-Option: When the main option changes, we reset
_selectedSubOptiontonullto avoid showing an invalid sub-option that doesn’t match the new main choice. - Conditional Rendering: The second dropdown only appears once a main option is selected (using the
ifstatement in the widget tree). - Form Validation: Both dropdowns include validation to ensure the user selects an option before submitting—you can remove this if it’s not needed for your use case.
Bonus: Dynamic Sub-Options (from API)
If your sub-options come from an API instead of a static map, modify the onChanged of the first dropdown to fetch data:
onChanged: (newValue) async { setState(() { _selectedMainOption = newValue; _selectedSubOption = null; }); // Fetch sub-options from API final subOptions = await _fetchSubOptions(newValue!); setState(() { _subOptionMap[newValue] = subOptions; }); },
This example should cover your exact requirements—feel free to tweak labels, sub-options, or styling to match your app’s design!
内容的提问来源于stack exchange,提问作者Sin Lee
相关产品推荐
相关产品推荐

