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

Flutter开发:API请求时如何在AppBar中显示LinearProgressIndicator

在Flutter AppBar中根据API请求状态显示进度条

核心思路

  • 用状态变量跟踪当前是否有API请求在进行
  • API请求发起时标记为加载状态,请求完成(成功/失败)后取消加载状态
  • 在AppBar中根据状态条件渲染LinearProgressIndicator

具体实现步骤

1. 管理加载状态

方案一:局部状态(适用于单个页面)

如果你的MenuScreen是StatefulWidget,直接在状态类中维护加载状态:

class MenuScreen extends StatefulWidget {
  @override
  State<MenuScreen> createState() => _MenuScreenState();
}

class _MenuScreenState extends State<MenuScreen> {
  bool _isLoading = false;

  // 更新加载状态的方法
  void _updateLoadingStatus(bool status) {
    setState(() {
      _isLoading = status;
    });
  }
}

方案二:全局状态(适用于多页面共享加载状态)

如果需要在多个页面同步显示加载状态,用ChangeNotifier实现全局状态管理:

class LoadingState extends ChangeNotifier {
  bool _isLoading = false;
  bool get isLoading => _isLoading;

  void setLoading(bool status) {
    _isLoading = status;
    notifyListeners();
  }
}

在main.dart中注册全局状态:

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => LoadingState(),
      child: const MyApp(),
    ),
  );
}

2. 改造API请求工具方法

不管用http、dio还是其他网络库,都要在请求前后更新加载状态,确保请求结束后(无论成功失败)进度条都会隐藏。

示例:基于http库的改造

class ApiService {
  // 全局状态方案:注入LoadingState
  final LoadingState? loadingState;
  // 局部状态方案:传递状态更新回调
  final void Function(bool)? updateLoading;

  ApiService({this.loadingState, this.updateLoading});

  Future<Map<String, dynamic>> login(String username, String password) async {
    // 标记加载开始
    loadingState?.setLoading(true);
    updateLoading?.call(true);
    
    try {
      final response = await http.post(
        Uri.parse('https://your-api-domain.com/login'),
        body: {'username': username, 'password': password},
      );
      return jsonDecode(response.body);
    } catch (e) {
      // 错误处理逻辑
      rethrow;
    } finally {
      // 请求结束,取消加载状态
      loadingState?.setLoading(false);
      updateLoading?.call(false);
    }
  }

  Future<List<dynamic>> fetchServerData() async {
    loadingState?.setLoading(true);
    updateLoading?.call(true);
    
    try {
      final response = await http.get(Uri.parse('https://your-api-domain.com/data'));
      return jsonDecode(response.body);
    } catch (e) {
      rethrow;
    } finally {
      loadingState?.setLoading(false);
      updateLoading?.call(false);
    }
  }
}

进阶:dio拦截器统一处理

如果用dio,可以通过拦截器统一管理加载状态,避免重复代码:

class LoadingInterceptor extends Interceptor {
  final LoadingState loadingState;

  LoadingInterceptor(this.loadingState);

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    loadingState.setLoading(true);
    super.onRequest(options, handler);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    loadingState.setLoading(false);
    super.onResponse(response, handler);
  }

  @override
  void onError(DioError err, ErrorInterceptorHandler handler) {
    loadingState.setLoading(false);
    super.onError(err, handler);
  }
}

// 初始化dio时添加拦截器
final dio = Dio();
dio.interceptors.add(LoadingInterceptor(LoadingState()));

3. 在AppBar中添加进度条

把LinearProgressIndicator作为AppBar的bottom属性,根据加载状态显示/隐藏:

局部状态方案

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('Menu Screen'),
      // 根据加载状态显示进度条
      bottom: _isLoading
          ? const PreferredSize(
              preferredSize: Size.fromHeight(2.0),
              child: LinearProgressIndicator(),
            )
          : null,
    ),
    body: // 页面内容
  );
}

全局状态方案

用Consumer监听全局状态变化:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('Menu Screen'),
      bottom: Consumer<LoadingState>(
        builder: (context, state, child) {
          return state.isLoading
              ? const PreferredSize(
                  preferredSize: Size.fromHeight(2.0),
                  child: LinearProgressIndicator(),
                )
              : null;
        },
      ),
    ),
    body: // 页面内容
  );
}

注意事项

  • 必须用finally块(或拦截器的响应/错误回调)取消加载状态,避免请求失败后进度条一直显示
  • 如果有多个并发请求,可以把isLoading改成计数器(请求开始+1,结束-1),计数器>0时显示进度条,防止进度条闪跳

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:25:14