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

如何使用flutter_bloc实现CircularProgressIndicator加载状态控制

Flutter Bloc 实现加载状态控制实操方案

核心逻辑说明

你不需要在页面组件内单独定义isLoading变量,所有状态统一交给Bloc管理即可:点击提交时只需要给Bloc发送事件,Bloc收到事件后先下发加载中状态,请求处理完成再下发结束加载的状态,页面通过BlocBuilder监听状态自动更新UI。

步骤1:定义包含加载标识的Bloc状态

这里提供两种常用实现方式,选一种即可:

方式A:单状态类内置isLoading字段(更易用,适合状态字段少的场景)

class ShowMusicHomeState {
  // 加载标识,默认false
  final bool isLoading;
  // 搜索结果
  final List<Track>? searchResult;
  // 错误提示
  final String? errorMsg;

  const ShowMusicHomeState({
    this.isLoading = false,
    this.searchResult,
    this.errorMsg,
  });

  // 快速拷贝修改部分字段
  ShowMusicHomeState copyWith({
    bool? isLoading,
    List<Track>? searchResult,
    String? errorMsg,
  }) {
    return ShowMusicHomeState(
      isLoading: isLoading ?? this.isLoading,
      searchResult: searchResult ?? this.searchResult,
      errorMsg: errorMsg ?? this.errorMsg,
    );
  }
}

方式B:密封类拆分不同状态(更规范,适合复杂业务场景)

sealed class ShowMusicHomeState {}
// 初始状态
class ShowMusicHomeInitial extends ShowMusicHomeState {}
// 加载中状态
class ShowMusicHomeLoading extends ShowMusicHomeState {}
// 加载成功状态
class ShowMusicHomeLoaded extends ShowMusicHomeState {
  final List<Track> searchResult;
  ShowMusicHomeLoaded(this.searchResult);
}
// 加载失败状态
class ShowMusicHomeError extends ShowMusicHomeState {
  final String errorMsg;
  ShowMusicHomeError(this.errorMsg);
}

步骤2:修改Bloc事件处理逻辑,控制加载状态流转

以方式A的状态为例,Bloc处理逻辑如下:

class ShowMusicHomeBloc extends Bloc<ShowMusicHomeEvent, ShowMusicHomeState> {
  // 初始化状态默认加载为false
  ShowMusicHomeBloc() : super(const ShowMusicHomeState()) {
    on<OnSearchTracks>(_handleSearchTracks);
  }

  Future<void> _handleSearchTracks(OnSearchTracks event, Emitter<ShowMusicHomeState> emit) async {
    // 1. 收到搜索事件,第一时间下发加载中状态
    emit(state.copyWith(isLoading: true, errorMsg: null));
    try {
      // 2. 执行你的实际搜索请求逻辑,比如调用后端接口
      final List<Track> result = await MusicApi.searchTracks(keyword: event.q);
      // 3. 请求成功,下发加载完成状态+搜索结果
      emit(state.copyWith(isLoading: false, searchResult: result));
    } catch (e) {
      // 4. 请求异常,下发加载完成状态+错误信息
      emit(state.copyWith(isLoading: false, errorMsg: e.toString()));
    }
  }
}

如果用方式B的密封类状态,只需要把emit的内容替换成对应状态类即可:

// 下发加载中
emit(ShowMusicHomeLoading());
// 下发成功
emit(ShowMusicHomeLoaded(result));
// 下发失败
emit(ShowMusicHomeError(e.toString()));

步骤3:页面层用BlocBuilder监听状态,渲染对应UI

你的按钮代码修改如下,不需要手动修改isLoading,全靠Bloc状态自动驱动:

BlocBuilder<ShowMusicHomeBloc, ShowMusicHomeState>(
  builder: (context, state) {
    return TextButton(
      // 加载状态下禁用按钮,防止重复提交
      onPressed: state.isLoading ? null : () {
        context.read<ShowMusicHomeBloc>().add(OnSearchTracks(q: _searchText.text));
        _searchText.clear();
      },
      // 根据状态切换显示文本/进度条
      child: state.isLoading 
          ? const CircularProgressIndicator(strokeWidth: 2, color: Colors.white)
          : const Text("submit"),
    );
  },
)

如果用方式B的密封类状态,builder里做类型判断即可:

BlocBuilder<ShowMusicHomeBloc, ShowMusicHomeState>(
  builder: (context, state) {
    final isLoading = state is ShowMusicHomeLoading;
    return TextButton(
      onPressed: isLoading ? null : () {
        context.read<ShowMusicHomeBloc>().add(OnSearchTracks(q: _searchText.text));
        _searchText.clear();
      },
      child: isLoading 
          ? const CircularProgressIndicator(strokeWidth: 2, color: Colors.white)
          : const Text("submit"),
    );
  },
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 22:15:02