You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何实现两个DropdownButton互斥禁用已选选项?

解决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(),
        ),
      ],
    );
  }
}

关键细节说明

  1. 状态共享:所有状态(选中值、可用选项)都在父State中管理,避免了独立State类之间的状态隔离问题
  2. 即时更新:每次调用setState()都会触发整个父组件重建,两个Dropdown会立即使用最新的可用选项列表
  3. 冲突处理:添加了重复选中的判断逻辑,防止两个Dropdown选中同一个选项(比如用户先选第一个的m,再选第二个的m时,自动把第一个切换为其他可用选项)
  4. 可选:禁用而非移除选项
    如果你不想移除选项,而是把已选中的选项置灰禁用,可以修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 17:42:15