Flutter中如何实现两个DropdownButton互斥禁用已选选项?
你的问题本质是两个Dropdown的状态完全独立,修改其中一个的选项列表时,另一个Dropdown不会触发重建,所以只有再次操作它才会刷新显示。要实现即时互斥,必须把两个Dropdown的状态放到同一个父组件中共享,这样一方变化时能同步触发另一方的UI更新。
核心解决思路
- 将两个Dropdown的选中值、选项生成逻辑统一放到父StatefulWidget中管理
- 每次选中某一Dropdown的选项时,立即更新对应状态,并为另一个Dropdown生成排除已选中选项的可用列表
- 通过父组件的
setState()触发两个Dropdown同时重建,实现即时更新
完整实现代码
import 'package:flutter/material.dart'; const List<String> tipolong = <String>[ 'mi', 'km', 'fur', 'hm', 'ch', 'dam', 'rd', 'm', 'yd', 'ft', 'dm', 'in', 'cm', 'mm' ]; class UnitConverter extends StatefulWidget { const UnitConverter({super.key}); @override State<UnitConverter> createState() => _UnitConverterState(); } class _UnitConverterState extends State<UnitConverter> { // 两个Dropdown的选中值,初始设为不同选项避免冲突 String? _selectedFrom = tipolong[0]; String? _selectedTo = tipolong[1]; // 生成第一个Dropdown的可用选项:排除第二个已选中的值 List<String> get _availableFromOptions { return tipolong.where((unit) => unit != _selectedTo).toList(); } // 生成第二个Dropdown的可用选项:排除第一个已选中的值 List<String> get _availableToOptions { return tipolong.where((unit) => unit != _selectedFrom).toList(); } @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // 第一个Dropdown DropdownButton<String>( value: _selectedFrom, icon: const Icon(Icons.arrow_downward), elevation: 16, style: const TextStyle(color: Colors.deepPurple), underline: Container( height: 2, color: Colors.deepPurpleAccent, ), onChanged: (String? newValue) { setState(() { _selectedFrom = newValue; // 如果新选中的值和第二个Dropdown的选中值重复,自动切换第二个的选中值到第一个可用选项 if (_selectedFrom == _selectedTo) { _selectedTo = _availableToOptions.first; } }); }, items: _availableFromOptions.map((unit) { return DropdownMenuItem<String>( value: unit, child: Text(unit), ); }).toList(), ), const SizedBox(width: 20), // 第二个Dropdown DropdownButton<String>( value: _selectedTo, icon: const Icon(Icons.arrow_downward), elevation: 16, style: const TextStyle(color: Colors.deepPurple), underline: Container( height: 2, color: Colors.deepPurpleAccent, ), onChanged: (String? newValue) { setState(() { _selectedTo = newValue; // 处理重复选中的情况 if (_selectedTo == _selectedFrom) { _selectedFrom = _availableFromOptions.first; } }); }, items: _availableToOptions.map((unit) { return DropdownMenuItem<String>( value: unit, child: Text(unit), ); }).toList(), ), ], ); } }
关键细节说明
- 状态共享:所有状态(选中值、可用选项)都在父State中管理,避免了独立State类之间的状态隔离问题
- 即时更新:每次调用
setState()都会触发整个父组件重建,两个Dropdown会立即使用最新的可用选项列表 - 冲突处理:添加了重复选中的判断逻辑,防止两个Dropdown选中同一个选项(比如用户先选第一个的
m,再选第二个的m时,自动把第一个切换为其他可用选项) - 可选:禁用而非移除选项
如果你不想移除选项,而是把已选中的选项置灰禁用,可以修改DropdownMenuItem的enabled属性:
// 示例:第一个Dropdown中禁用第二个已选中的选项 items: tipolong.map((unit) { return DropdownMenuItem<String>( value: unit, enabled: unit != _selectedTo, // 禁用已被另一个Dropdown选中的选项 child: Text( unit, style: TextStyle( color: unit == _selectedTo ? Colors.grey : Colors.deepPurple, ), ), ); }).toList(),
内容的提问来源于stack exchange,提问作者Mad Beatx
相关产品推荐
相关产品推荐

