Flutter如何通过编程方式打开Stack布局内的DropdownButton下拉框
解决方案
核心问题说明
- 现有实现用Stack嵌套DropdownButton和TextField,上层TextField完全遮挡下层DropdownButton的点击区域,无法手动触发点击
- 原生DropdownButton未暴露公开的展开API,之前尝试的反射调用方案容易因为Flutter版本迭代失效
- Stack中冗余的DropdownButton构建逻辑属于无效代码,无实际作用
修正方案
方案1:使用官方Autocomplete组件(推荐)
官方自带的Autocomplete组件原生支持输入触发搜索、展示下拉选项的需求,不需要额外hack Dropdown的展开逻辑,适配性最好。
方案2:手动触发DropdownButton点击事件
如果你需要继续使用DropdownButton实现,按以下步骤修改代码:
- 将通用GlobalKey替换为指定DropdownButton状态类型的Key,用于获取组件状态
- 接口返回数据更新选项列表后,调用状态内部的tap方法触发下拉展开
- 移除Stack中冗余的DropdownButton代码,直接将TextField作为DropdownButton的自定义点击区域,避免遮挡问题
修正后代码
import 'package:flutter/material.dart'; import 'package:giphy/services/gifs_service.dart'; import 'package:giphy/shared/autocomplete.dart'; class TestDropDown extends StatefulWidget { @override _TestDropDownState createState() => _TestDropDownState(); } class _TestDropDownState extends State<TestDropDown> { final GifyService _service = GifyService(); final TextEditingController _gifSearchController = TextEditingController(); List<SearchData> _dropDownResult = <SearchData>[]; // 指定具体的DropdownButton状态类型 final GlobalKey<DropdownButtonState<String>> dropdownKey = GlobalKey(); Widget _buildDropDown(List<SearchData> searchData) => DropdownButton<String>( isExpanded: true, key: dropdownKey, underline: const SizedBox.shrink(), // 去掉默认下划线 onChanged: (String? value) { // 选中后更新输入框内容 if(value != null) { _gifSearchController.text = value; } }, // 选中状态不额外展示选中项,直接显示输入框 selectedItemBuilder: (context) => searchData.map((e) => const SizedBox.shrink()).toList(), hint: TextField( controller: _gifSearchController, decoration: InputDecoration( border: OutlineInputBorder( borderSide: const BorderSide(width: 0.5), borderRadius: BorderRadius.circular(21), ), ), onChanged: (String value) async { AutoComplete result = await _service.getSearchKeywords(value); setState(() { _dropDownResult = result.data; }); // 有返回结果时自动展开下拉框 if(_dropDownResult.isNotEmpty) { dropdownKey.currentState?.tap(); } }, ), items: searchData .map( (e) => DropdownMenuItem<String>( child: Text(e.name ?? ''), value: e.name ?? '', ), ) .toList(), ); @override Widget build(BuildContext context) { return Scaffold( body: Padding( padding: const EdgeInsets.all(20), child: _buildDropDown(_dropDownResult), ), ); } }
内容的提问来源于stack exchange,提问作者Yaseen
相关产品推荐
相关产品推荐

