Flutter自定义DropDownButton类下拉列表无法展开问题求助
问题描述
通过自定义类封装DropdownButtonFormField组件时,下拉列表无法展开,按钮点击后无响应。已确认数据源有效,因需要创建多个同类按钮,故采用类封装减少重复代码。
错误分析
- 状态保存方法未正确返回函数:
saveStateCountry方法内部定义了回调函数,但没有返回该函数,导致传递给组件的saveState参数无效。 - 组件内
onChanged未调用回调:在DropdownButtonFormField的onChanged中仅引用saveState,未实际调用它传递选中值。 - hint文本写死:组件内
hint使用了固定字符串'hintDropDown',未使用传入的hintDropDown参数。 - 回调类型定义不严谨:自定义组件的
saveState参数类型为Function,应明确为void Function(dynamic)以保证类型安全。
修复后的代码
1. 修复后的自定义DropDownButtons组件
class DropDownButtons extends StatelessWidget { final dynamic valueDropDown; final String hintDropDown; final List<DropdownMenuItem<dynamic>>? itemsDropDown; final void Function(dynamic) saveState; // 明确回调类型 const DropDownButtons({ Key? key, required this.valueDropDown, required this.hintDropDown, required this.itemsDropDown, required this.saveState, }) : super(key: key); @override Widget build(BuildContext context) { return Container( width: 270, margin: const EdgeInsets.only(top: 7), child: Align( alignment: Alignment.center, child: DropdownButtonFormField( decoration: InputDecoration( border: OutlineInputBorder( borderRadius: const BorderRadius.all(Radius.circular(25.0)), ), fillColor: Colors.lightBlueAccent.withOpacity(0.2), filled: true, ), hint: Text(hintDropDown), // 使用传入的hint参数 value: valueDropDown, icon: const Icon(Icons.keyboard_arrow_down), items: itemsDropDown, onChanged: (dynamic newValue) { if (newValue != null) { saveState(newValue); // 调用回调并传递选中值 } }, ), ), ); } }
2. 修复后的状态保存方法
void Function(dynamic) saveStateCountry() { // 返回内部定义的回调函数 return (dynamic newValue) { setState(() { LoginClass.countryValue = newValue; print(LoginClass.countryValue); }); }; }
3. 修复后的组件调用代码
DropDownButtons( valueDropDown: LoginClass.countryValue, hintDropDown: 'Выберите страну', itemsDropDown: LoginClass.countryDropDown, saveState: saveStateCountry(), // 调用方法获取有效回调 ),
完整可复现代码
import 'package:flutter/material.dart'; // 假设的LoginClass,需确保countryValue和countryDropDown已正确初始化 class LoginClass { static dynamic countryValue; static List<DropdownMenuItem<dynamic>> countryDropDown = [ const DropdownMenuItem(value: 'RU', child: Text('Россия')), const DropdownMenuItem(value: 'US', child: Text('США')), const DropdownMenuItem(value: 'CN', child: Text('Китай')), ]; } class CreatedApplications extends StatelessWidget { const CreatedApplications({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData(primarySwatch: Colors.blue), home: const MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { DateTime now = DateTime.now(); void Function(dynamic) saveStateCountry() { return (dynamic newValue) { setState(() { LoginClass.countryValue = newValue; print(LoginClass.countryValue); }); }; } @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: false, body: SingleChildScrollView( padding: const EdgeInsets.all(15), child: Column( children: [ Column( children: <Widget>[ Align( alignment: Alignment.center, child: FractionallySizedBox( widthFactor: 1, alignment: Alignment.centerLeft, child: Text('${now}'), ), ), ], ), const SizedBox(height: 12), DropDownButtons( valueDropDown: LoginClass.countryValue, hintDropDown: 'Выберите страну', itemsDropDown: LoginClass.countryDropDown, saveState: saveStateCountry(), ), ], ), ), ); } } class DropDownButtons extends StatelessWidget { final dynamic valueDropDown; final String hintDropDown; final List<DropdownMenuItem<dynamic>>? itemsDropDown; final void Function(dynamic) saveState; const DropDownButtons({ Key? key, required this.valueDropDown, required this.hintDropDown, required this.itemsDropDown, required this.saveState, }) : super(key: key); @override Widget build(BuildContext context) { return Container( width: 270, margin: const EdgeInsets.only(top: 7), child: Align( alignment: Alignment.center, child: DropdownButtonFormField( decoration: InputDecoration( border: OutlineInputBorder( borderRadius: const BorderRadius.all(Radius.circular(25.0)), ), fillColor: Colors.lightBlueAccent.withOpacity(0.2), filled: true, ), hint: Text(hintDropDown), value: valueDropDown, icon: const Icon(Icons.keyboard_arrow_down), items: itemsDropDown, onChanged: (dynamic newValue) { if (newValue != null) { saveState(newValue); } }, ), ), ); } }
额外说明
- 确保
LoginClass中的countryDropDown已正确生成DropdownMenuItem列表,且每个item的value与countryValue类型一致。 - 若
countryValue初始值为null,需确保itemsDropDown中没有对应的value为null的item,否则下拉列表可能无法正常显示hint。
内容的提问来源于stack exchange,提问作者Daniil
相关产品推荐
相关产品推荐

