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
相关产品推荐
相关产品推荐

