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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 23:52:46