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

Flutter自定义Dropdown组件下拉项显示异常修复方案

Flutter自定义Dropdown组件下拉项遮挡输入框修复

我在Flutter项目中实现了一个自定义Dropdown组件,但调用时下拉项显示异常——会遮挡输入框,期望实现下拉项在输入框下方整齐展开的效果。

原代码

import 'package:flutter/material.dart';
import 'package:universalteam/Components/AppColors.dart';

Widget CustomDropdown({
  required List<String> items,
  required String hint,
  double borderRadius = 16,
  double width = double.infinity,
  double height = 60,
  double left = 0,
  double right = 0,
  double top = 0,
  double bottom = 0,
  double fontSize = 16,
  Color color = AppColors.black,
  Color containerBackgroundColor = AppColors.RegisterPageTextFieldColor,
  Color textFieldBackgroundColor = AppColors.RegisterPageTextFieldColor,
  double contentPaddingLeft = 12,
  double contentPaddingRight = 0,
  TextAlign textalign = TextAlign.left,
  bool isRequired = false,
  void Function(String?)? onChanged,
}) {
  String? _selectedItem;

  return Visibility(
    visible: true,
    child: Container(
      width: width,
      height: height,
      padding: EdgeInsets.only(
        left: left,
        right: right,
        top: top,
        bottom: bottom,
      ),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
        color: containerBackgroundColor,
      ),
      child: Container(
        alignment: Alignment.center,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
          color: textFieldBackgroundColor,
        ),
        child: DropdownButtonFormField<String>(
          value: _selectedItem,
          style: TextStyle(
            fontSize: fontSize,
            fontFamily: "Poppins",
            fontWeight: FontWeight.w400,
            color: AppColors.black,
          ),
          decoration: InputDecoration(
            label: RichText(
              softWrap: true,
              text: TextSpan(
                text: hint,
                style: TextStyle(
                  color: AppColors.darkGray,
                ),
                children: [
                  isRequired == true
                      ? TextSpan(
                          text: ' * ',
                          style: TextStyle(
                            color: AppColors.darkMagenta,
                            fontWeight: FontWeight.bold,
                          ),
                        )
                      : TextSpan(text: '')
                ],
              ),
            ),
            border: InputBorder.none,
            contentPadding: EdgeInsets.only(
              left: contentPaddingLeft,
              right: contentPaddingRight,
            ),
            suffixIcon: Icon(
              Icons.keyboard_arrow_down,
              size: 25,
              color: AppColors.darkMagenta,
            ),
          ),
          onChanged: (String? newValue) {
            _selectedItem = newValue;
            onChanged?.call(newValue);
          },
          items: items.map<DropdownMenuItem<String>>((String value) {
            return DropdownMenuItem<String>(
              value: value,
              child: Text(
                value,
                textAlign: TextAlign.center,
                style: TextStyle(
                  color: Color(0xFF5F5F60),
                  fontSize: 13,
                  fontFamily: 'Poppins',
                  fontWeight: FontWeight.w400,
                  height: 0.12,
                ),
              ),
            );
          }).toList(),
          icon: SizedBox(),
        ),
      ),
    ),
  );
}

当前效果

下拉项遮挡输入框

期望效果

下拉项在输入框下方整齐展开

问题原因

  1. 外层Container设置了固定height: 60,约束了Dropdown下拉弹窗的显示空间,导致弹窗被挤压遮挡输入框。
  2. 多层嵌套Container干扰了Dropdown弹窗的默认定位逻辑。
  3. 用StatelessWidget维护选中状态_selectedItem,组件重建时状态会丢失,无法触发UI更新。
  4. 未设置isExpanded属性,下拉项宽度与输入框不一致。

修改后的代码

import 'package:flutter/material.dart';
import 'package:universalteam/Components/AppColors.dart';

class CustomDropdown extends StatefulWidget {
  final List<String> items;
  final String hint;
  final double borderRadius;
  final double width;
  final double left;
  final double right;
  final double top;
  final double bottom;
  final double fontSize;
  final Color color;
  final Color containerBackgroundColor;
  final Color textFieldBackgroundColor;
  final double contentPaddingLeft;
  final double contentPaddingRight;
  final TextAlign textalign;
  final bool isRequired;
  final void Function(String?)? onChanged;

  const CustomDropdown({
    super.key,
    required this.items,
    required this.hint,
    this.borderRadius = 16,
    this.width = double.infinity,
    this.left = 0,
    this.right = 0,
    this.top = 0,
    this.bottom = 0,
    this.fontSize = 16,
    this.color = AppColors.black,
    this.containerBackgroundColor = AppColors.RegisterPageTextFieldColor,
    this.textFieldBackgroundColor = AppColors.RegisterPageTextFieldColor,
    this.contentPaddingLeft = 12,
    this.contentPaddingRight = 0,
    this.textalign = TextAlign.left,
    this.isRequired = false,
    this.onChanged,
  });

  @override
  State<CustomDropdown> createState() => _CustomDropdownState();
}

class _CustomDropdownState extends State<CustomDropdown> {
  String? _selectedItem;

  @override
  Widget build(BuildContext context) {
    return Visibility(
      visible: true,
      child: Container(
        width: widget.width,
        padding: EdgeInsets.only(
          left: widget.left,
          right: widget.right,
          top: widget.top,
          bottom: widget.bottom,
        ),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.all(Radius.circular(widget.borderRadius)),
          color: widget.containerBackgroundColor,
        ),
        child: DropdownButtonFormField<String>(
          value: _selectedItem,
          dropdownColor: widget.textFieldBackgroundColor,
          isExpanded: true,
          style: TextStyle(
            fontSize: widget.fontSize,
            fontFamily: "Poppins",
            fontWeight: FontWeight.w400,
            color: AppColors.black,
          ),
          decoration: InputDecoration(
            label: RichText(
              softWrap: true,
              text: TextSpan(
                text: widget.hint,
                style: const TextStyle(
                  color: AppColors.darkGray,
                ),
                children: [
                  widget.isRequired
                      ? const TextSpan(
                          text: ' * ',
                          style: TextStyle(
                            color: AppColors.darkMagenta,
                            fontWeight: FontWeight.bold,
                          ),
                        )
                      : const TextSpan(text: '')
                ],
              ),
            ),
            border: InputBorder.none,
            filled: true,
            fillColor: widget.textFieldBackgroundColor,
            contentPadding: EdgeInsets.only(
              left: widget.contentPaddingLeft,
              right: widget.contentPaddingRight,
              top: 16,
              bottom: 16,
            ),
            suffixIcon: const Icon(
              Icons.keyboard_arrow_down,
              size: 25,
              color: AppColors.darkMagenta,
            ),
          ),
          onChanged: (String? newValue) {
            setState(() {
              _selectedItem = newValue;
            });
            widget.onChanged?.call(newValue);
          },
          items: widget.items.map<DropdownMenuItem<String>>((String value) {
            return DropdownMenuItem<String>(
              value: value,
              child: Text(
                value,
                textAlign: widget.textalign,
                style: const TextStyle(
                  color: Color(0xFF5F5F60),
                  fontSize: 13,
                  fontFamily: 'Poppins',
                  fontWeight: FontWeight.w400,
                ),
              ),
            );
          }).toList(),
          icon: const SizedBox(),
        ),
      ),
    );
  }
}

关键修改说明

  • 重构为StatefulWidget,通过setState维护选中状态,确保UI能正确响应选择变化。
  • 移除外层Container的固定高度,释放下拉弹窗的显示约束。
  • 设置isExpanded: true,让下拉项宽度与输入框完全匹配。
  • 使用filled: true和fillColor替代嵌套Container,简化背景布局,避免层级干扰。
  • 添加dropdownColor,保证下拉弹窗背景与输入框视觉统一。
  • 调整contentPadding的上下值,确保输入框内容垂直居中,同时避免高度限制问题。

内容的提问来源于stack exchange,提问作者a a

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 13:44:54