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

Flutter自定义DropDownButton类下拉列表无法展开问题求助

自定义DropdownButton无法展开的问题修复

问题描述

通过自定义类封装DropdownButtonFormField组件时,下拉列表无法展开,按钮点击后无响应。已确认数据源有效,因需要创建多个同类按钮,故采用类封装减少重复代码。

错误分析

  1. 状态保存方法未正确返回函数:saveStateCountry方法内部定义了回调函数,但没有返回该函数,导致传递给组件的saveState参数无效。
  2. 组件内onChanged未调用回调:在DropdownButtonFormField的onChanged中仅引用saveState,未实际调用它传递选中值。
  3. hint文本写死:组件内hint使用了固定字符串'hintDropDown',未使用传入的hintDropDown参数。
  4. 回调类型定义不严谨:自定义组件的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:15:42