Flutter中DefaultTabController的3个TabBar共用同一WidgetOfTape的实现方法
实现方案
第一步:改造WidgetOfTape,新增固定索引入参
你原来的写法所有WidgetOfTape都依赖全局统一的选中索引状态,切换Tab时会触发所有页面重复重建,性能很差。我们直接给每个页面实例传入独立的固定索引,每个页面自己管理对应索引的数据即可,无需依赖全局选中状态:
class WidgetOfTape extends HookWidget { // 新增索引入参,每个实例对应不同的Tab索引 const WidgetOfTape({super.key, required this.tabIndex}); final int tabIndex; @override Widget build(BuildContext context) { // 移除原来的BlocSelector,直接用自身持有的tabIndex拉取数据 return BlocProvider<DisplayNoteInsidePagesCubit>( lazy: false, create: (context) => getIt<DisplayNoteInsidePagesCubit>() ..countDoneNoteOutOfAllNotes() // 直接传入当前实例的固定索引 ..retrieveData(indexOfTap: tabIndex), child: Column(children: [ Expanded(child: BlocBuilder<DisplayNoteInsidePagesCubit, DisplayNoteInsidePagesState>( builder: (context, state) { return ListView.builder( shrinkWrap: true, itemCount: state.notes.length, itemBuilder: (BuildContext context, int index) { return Row( children: [ Expanded( child: Text( state.notes[index]['content'], textAlign: TextAlign.justify, style: Theme.of(context).textTheme.bodyText2, ), ), ], ); }); }, )) ])); } }
注意:确保你的getIt注册DisplayNoteInsidePagesCubit时用的是factory模式,而不是单例模式,否则三个Tab会拿到同一个Cubit实例导致数据冲突
第二步:改造TabBarView的子节点配置
给三个WidgetOfTape分别传入对应的索引0、1、2即可,无需重复写三份页面代码:
DefaultTabController( length: 3, child: Scaffold( body: const TabBarView( children: [ WidgetOfTape(tabIndex: 0), WidgetOfTape(tabIndex: 1), WidgetOfTape(tabIndex: 2), ], ), ) )
可选优化:页面保活
如果需要切换Tab后不销毁已加载的页面、保留滚动位置和数据,可以给WidgetOfTape混入AutomaticKeepAliveClientMixin:
class WidgetOfTape extends HookWidget with AutomaticKeepAliveClientMixin { const WidgetOfTape({super.key, required this.tabIndex}); final int tabIndex; // 开启保活 @override bool get wantKeepAlive => true; @override Widget build(BuildContext context) { // 必须调用super.build super.build(context); // 其余代码和上面改造后的一致 } }
如果需要每次切回Tab时都刷新最新数据,可以监听DefaultTabController的索引变化,当当前页面索引和选中索引一致时,调用Cubit的retrieveData方法刷新即可。
内容的提问来源于stack exchange,提问作者Mariam Albarghouti
相关产品推荐
相关产品推荐

