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

Flutter如何实现API数据下拉菜单展示并存储选中项ID

适配Flutter 3.x 空安全版本的实现方案

1. 前置配置

  • 先在pubspec.yaml的dependencies节点下添加网络请求依赖:
dependencies:
  flutter:
    sdk: flutter
  http: ^1.2.2 # 使用当前最新稳定版即可,原生支持空安全
  • 安卓端需要在android/app/src/main/AndroidManifest.xml的<manifest>根节点下、<application>标签之前添加网络权限,否则请求会被系统拦截:
<uses-permission android:name="android.permission.INTERNET" />
  • 配置完成后执行flutter pub get拉取依赖包。

2. 定义用户数据模型

目标接口返回的data数组字段结构固定,手写简单解析逻辑即可,无需额外引入第三方序列化库:

class User {
  final int id;
  final String firstName;
  final String lastName;
  final String email;

  User({
    required this.id,
    required this.firstName,
    required this.lastName,
    required this.email,
  });

  // 从json map转换为模型对象
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int,
      firstName: json['first_name'] as String,
      lastName: json['last_name'] as String,
      email: json['email'] as String,
    );
  }

  // 下拉菜单展示的用户名称
  String get displayName => '$firstName $lastName';
}

3. 完整页面实现

用StatefulWidget管理三类状态:加载状态、用户列表数据、选中的用户ID,页面初始化时自动触发接口请求,下拉选项选中时直接更新ID变量:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class UserDropdownPage extends StatefulWidget {
  const UserDropdownPage({super.key});

  @override
  State<UserDropdownPage> createState() => _UserDropdownPageState();
}

class _UserDropdownPageState extends State<UserDropdownPage> {
  List<User> _userList = [];
  int? selectedUserId; // 选中项的ID直接存在该变量中
  bool _isLoading = true;
  String? _errorMsg;

  @override
  void initState() {
    super.initState();
    _fetchUserList();
  }

  // 拉取接口数据
  Future<void> _fetchUserList() async {
    try {
      final response = await http.get(
        Uri.parse('https://reqres.in/api/users?page=1'),
      );
      if (response.statusCode == 200) {
        // 用utf8解码响应避免特殊字符乱码
        final jsonData = json.decode(utf8.decode(response.bodyBytes));
        final dataList = jsonData['data'] as List;
        _userList = dataList.map((item) => User.fromJson(item)).toList();
        _errorMsg = null;
      } else {
        _errorMsg = '请求失败,状态码:${response.statusCode}';
      }
    } catch (e) {
      _errorMsg = '网络异常:${e.toString()}';
    } finally {
      if (mounted) {
        setState(() {
          _isLoading = false;
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('用户下拉选择')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: _buildContent(),
      ),
    );
  }

  Widget _buildContent() {
    // 加载中展示进度条
    if (_isLoading) {
      return const Center(child: CircularProgressIndicator());
    }
    // 请求失败展示错误提示和重试按钮
    if (_errorMsg != null) {
      return Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(_errorMsg!, style: const TextStyle(color: Colors.red)),
            const SizedBox(height: 12),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  _isLoading = true;
                  _errorMsg = null;
                });
                _fetchUserList();
              },
              child: const Text('重试'),
            )
          ],
        ),
      );
    }
    // 数据加载完成展示下拉菜单
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        const Text('请选择用户:', style: TextStyle(fontSize: 16)),
        const SizedBox(height: 8),
        DropdownButton<int>(
          isExpanded: true, // 下拉框撑满父容器宽度
          value: selectedUserId,
          hint: const Text('请选择'),
          items: _userList.map((User user) {
            return DropdownMenuItem<int>(
              value: user.id,
              child: Text(user.displayName),
            );
          }).toList(),
          onChanged: (int? newId) {
            setState(() {
              selectedUserId = newId;
            });
            // 此处可直接拿到选中ID执行后续业务逻辑
            debugPrint('当前选中用户id:$selectedUserId');
          },
        ),
        const SizedBox(height: 24),
        if (selectedUserId != null)
          Text('当前选中的用户ID:$selectedUserId', style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold))
      ],
    );
  }
}

关键说明

  • 所有写法完全适配Dart 3.x/Flutter 3.x空安全规范,未使用任何已废弃的API
  • 网络请求做了完整的异常捕获、状态码判断,覆盖加载/错误/成功三态,复制代码即可直接运行
  • DropdownButton的value直接绑定用户ID,选中时直接赋值给目标变量,无需额外转换
  • 解析响应时使用utf8.decode(response.bodyBytes)处理数据,避免特殊字符、中文乱码问题
  • 异步回调中加入mounted判断,避免请求完成后页面已销毁导致的内存泄漏和报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 08:21:24