Flutter下拉框调用API:每次重载显示CircularProgressIndicator实现
解决方案
要实现每次调用add函数时让Dropdown替换为加载指示器,你需要手动控制异步请求的触发时机,并完善状态判断逻辑,具体步骤如下:
1. 重构异步请求的管理方式
把异步请求的Future对象抽成组件的成员变量,避免每次组件重建时自动发起请求,同时让我们能手动触发新的请求:
// 定义成员变量存储当前的异步请求Future Future<List<DropdownMenuItem<String>>>? _dropdownFuture; @override void initState() { super.initState(); // 初始化时加载第一次数据 _dropdownFuture = add(); }
2. 添加手动触发刷新的方法
创建一个方法来重新发起add请求,通过更新_dropdownFuture的值触发FutureBuilder重建:
void _refreshDropdownData() { setState(() { // 重新赋值Future,触发FutureBuilder重新执行异步请求 _dropdownFuture = add(); }); }
3. 完善FutureBuilder的状态判断
修改FutureBuilder的逻辑,明确判断异步请求的状态,在请求进行中时显示加载指示器:
FutureBuilder<List<DropdownMenuItem<String>>>( future: _dropdownFuture, builder: (context, snapshot) { // 请求正在进行时显示加载指示器 if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } // 请求成功且有数据时显示Dropdown else if (snapshot.hasData) { var data = snapshot.data!; return DropdownButton( value: selectedValue, items: data, // 原代码的map操作多余,可直接使用data onChanged: (String? value) { setState(() { selectedValue = value!; }); }, ); } // 请求出错时显示错误提示(可选) else if (snapshot.hasError) { return Text('加载失败: ${snapshot.error}'); } // 默认显示加载指示器 else { return const CircularProgressIndicator(); } }, )
4. 添加触发刷新的UI元素
比如添加一个按钮,点击时调用刷新方法,就能看到每次请求时Dropdown被替换为加载指示器:
// 在Column的children里添加 ElevatedButton( onPressed: _refreshDropdownData, child: const Text('刷新数据'), ),
完整修改后的代码
import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; class DropdownPage extends StatefulWidget { const DropdownPage({super.key, required this.title}); final String title; @override State<DropdownPage> createState() => _DropdownPageState(); } class _DropdownPageState extends State<DropdownPage> { Future<List<DropdownMenuItem<String>>> add() async { List<DropdownMenuItem<String>> menuItems = [ const DropdownMenuItem(value: "0", child: Text("USA")), const DropdownMenuItem(value: "1", child: Text("Canada")) ]; var url = Uri.http("localhost:8080", "/province"); var response = await http.get(url); // 可根据API返回数据更新menuItems,示例暂用初始数据 return menuItems; } String selectedValue = "0"; // 初始值需与menuItems中某个value匹配,避免报错 Future<List<DropdownMenuItem<String>>>? _dropdownFuture; @override void initState() { super.initState(); _dropdownFuture = add(); } void _refreshDropdownData() { setState(() { _dropdownFuture = add(); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text( '选择国家:', ), const SizedBox(height: 16), FutureBuilder<List<DropdownMenuItem<String>>>( future: _dropdownFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } else if (snapshot.hasData) { var data = snapshot.data!; return DropdownButton( value: selectedValue, items: data, onChanged: (String? value) { setState(() { selectedValue = value!; }); }, ); } else if (snapshot.hasError) { return Text('加载失败: ${snapshot.error}'); } else { return const CircularProgressIndicator(); } }, ), const SizedBox(height: 16), ElevatedButton( onPressed: _refreshDropdownData, child: const Text('刷新数据'), ), ], ), ), ); } }
关键说明
- 将
Future抽为成员变量后,只有主动调用_refreshDropdownData更新它时,才会发起新请求,避免不必要的重复请求。 - 通过
ConnectionState.waiting精准捕获请求进行中的状态,此时显示加载指示器。 - 初始
selectedValue必须与menuItems中的某个value匹配,否则Dropdown会抛出错误。
内容的提问来源于stack exchange,提问作者Mario Rovelli
相关产品推荐
相关产品推荐

