如何使用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
相关产品推荐
相关产品推荐

