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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 21:24:08