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

Flutter:如何从API获取数据填充下拉框并获取选中项

解决方案

1. 定义Station数据模型

先创建对应API返回结构的数据模型,方便后续解析和处理:

class Station {
  final int id;
  final String name;
  final String address;
  final String imageUrl;

  Station({
    required this.id,
    required this.name,
    required this.address,
    required this.imageUrl,
  });

  // 根据你的API返回格式,调整JSON解析逻辑
  factory Station.fromJson(Map<String, dynamic> json) {
    return Station(
      id: json['id'],
      name: json['name'],
      address: json['address'],
      imageUrl: json['image_url'] ?? 'assets/images/poynt.jpg', // 本地图作为默认值
    );
  }
}

2. 修改下拉组件,支持动态数据与选中回调

把硬编码的下拉项改成接收外部传入的stations列表,同时添加回调传递选中的Station对象:

class PoyntsDropDownWidget extends StatefulWidget {
  final List<Station> stations;
  final Station? selectedStation;
  final Function(Station) onStationSelected;

  const PoyntsDropDownWidget({
    super.key,
    required this.stations,
    required this.selectedStation,
    required this.onStationSelected,
  });

  @override
  State<PoyntsDropDownWidget> createState() => _PoyntsDropDownWidgetState();
}

class _PoyntsDropDownWidgetState extends State<PoyntsDropDownWidget> {
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      padding: const EdgeInsets.only(left: 20, right: 13),
      decoration: BoxDecoration(
        color: constants.Colors.greyXDark,
        borderRadius: BorderRadius.circular(20),
        boxShadow: const [
          BoxShadow(
            color: Colors.black26,
            spreadRadius: 5,
            blurRadius: 12,
            offset: Offset(0, 0),
          )
        ],
      ),
      child: DropdownButton<Station>(
        isExpanded: true,
        itemHeight: 100,
        icon: const SizedBox.shrink(),
        value: widget.selectedStation,
        onChanged: (Station? value) {
          if (value != null) widget.onStationSelected(value);
        },
        underline: const SizedBox(),
        dropdownColor: constants.Colors.greyXDark,
        items: widget.stations.map((Station station) {
          return DropdownMenuItem<Station>(
            value: station,
            child: Row(
              children: [
                SizedBox(
                  height: 80,
                  width: 80,
                  child: ClipRRect(
                    borderRadius: BorderRadius.circular(8),
                    // 兼容网络图片和本地图片
                    child: station.imageUrl.startsWith('http')
                        ? Image.network(station.imageUrl, fit: BoxFit.cover)
                        : Image.asset(station.imageUrl, fit: BoxFit.cover),
                  ),
                ),
                const SizedBox(width: 15),
                Expanded(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Text(
                        station.name,
                        maxLines: 2,
                        overflow: TextOverflow.ellipsis,
                        style: constants.Styles.normalHeavyTextStyleWhite,
                      ),
                      const SizedBox(height: 6),
                      FittedBox(
                        fit: BoxFit.scaleDown,
                        child: Text(
                          station.address,
                          style: constants.Styles.smallBookTextStyleWhite,
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          );
        }).toList(),
      ),
    );
  }
}

3. 在页面中集成下拉组件并展示选中数据

在你的状态管理页面(比如Bloc/Cubit对应的UI)中,保存选中的Station状态,传递给下拉组件并展示对应数据:

// 在页面State中添加选中状态变量
Station? _selectedStation;

// 处理StationLoaded状态时的逻辑
if (state is StationLoaded) {
  // 初始化选中第一个站点(可选)
  _selectedStation ??= state.stations.isNotEmpty ? state.stations[0] : null;

  return Column(
    children: [
      // 集成下拉组件
      PoyntsDropDownWidget(
        stations: state.stations,
        selectedStation: _selectedStation,
        onStationSelected: (Station station) {
          setState(() => _selectedStation = station);
        },
      ),
      // 展示选中站点的对应数据
      if (_selectedStation != null)
        Container(
          margin: const EdgeInsets.only(top: 20),
          padding: const EdgeInsets.all(16),
          color: constants.Colors.greyXDark,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                '选中站点:${_selectedStation!.name}',
                style: constants.Styles.normalHeavyTextStyleWhite,
              ),
              const SizedBox(height: 8),
              Text(
                '地址:${_selectedStation!.address}',
                style: constants.Styles.smallBookTextStyleWhite,
              ),
              // 可添加更多需要展示的字段
            ],
          ),
        ),
      // 保留原来的ListView部分
      Expanded(
        child: Container(
          height: MediaQuery.of(context).size.height,
          decoration: const BoxDecoration(
            color: constants.Colors.greyXDark,
            border: Border(
              left: BorderSide(width: 2, color: constants.Colors.purpleMain),
              right: BorderSide(width: 2, color: constants.Colors.purpleMain),
              bottom: BorderSide(width: 2, color: constants.Colors.purpleMain),
            ),
          ),
          child: Padding(
            padding: const EdgeInsets.only(top: 40, left: 14, right: 14),
            child: MediaQuery.removePadding(
              context: context,
              removeTop: true,
              child: ListView.builder(
                physics: const BouncingScrollPhysics(),
                itemCount: state.stations.length + 1,
                itemBuilder: (context, index) {
                  if (index == state.stations.length) {
                    // 原来的底部内容逻辑
                    return const SizedBox();
                  } else {
                    // 原来的列表项渲染逻辑
                    return ListTile(
                      title: Text(state.stations[index].name),
                    );
                  }
                },
              ),
            ),
          ),
        ),
      ),
    ],
  );
}

关键说明

  • 下拉组件不再依赖硬编码数据,通过stations参数接收API返回列表,复用性更强
  • 直接用Station对象作为下拉项的value,避免索引映射的麻烦,选中后直接拿到完整数据
  • 选中回调onStationSelected将选中的Station传递给父页面,父页面保存状态后即可展示对应内容
  • 图片部分兼容网络图和本地图,根据API返回的imageUrl自动切换

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 02:10:36