flutter pull_to_refresh 结合getx报
Don’t use one refreshController to multiple SmartRefresher,It will cause some unexpected bugs mostly in TabBarView ‘package:pull_to_refresh_flutter3/src/smart_refresher.dart’: Failed assertion: line 548 pos 12: '_refresherState == null
一般这种问题,是因为 Getx的每个GetxController 要对应SmartRefresher 各自独立RefreshController , 如果相同的 我的GetxController 要加tag区分,我的每个GetX对应各自的refreshController,GetxController 是各自的,Getx也加了Tag个,按理说不会有这个问题,正常打开使用没问题,但是当用户按了back键后,在快速点击ListView必报这个,代码如下

  ///外部传参RefreshController
  RefreshController? refreshController;

  ///子类,必须是ListView-ScrolleView等
  Widget? child;

  @override
  Widget build(BuildContext context) {
    return ScrollConfiguration(
        behavior: OverScrollBehavior(),
        child: SmartRefresher(
            key: key,
            controller: refreshController ?? controller.refreshController,
            enablePullDown: enablePullDown,
            enablePullUp: enablePullUp,
            onRefresh: () => controller.onLoadRefresh(),
            onLoading: () => controller.onLoadMore(),
            header: ClassicHeader(
              releaseText: ID.releaseText.tr,
              refreshingText: ID.refreshingText.tr,
              completeText: ID.completeText.tr,
              idleText: ID.idleText.tr,
              textStyle: TextStyle(
                  fontSize: Get.setFontSize(14),
                  fontFamily: Get.setFontFamily(),
                  fontWeight: FontWeightX.regular,
                  color: Get.theme.textSecondary,
                  overflow: TextOverflow.ellipsis),
            ),
            footer: ClassicFooter(
              loadingText: ID.loadingText.tr,
              idleText: ID.pullUpToLoad.tr,
              canLoadingText: ID.canLoadingText.tr,
              textStyle: TextStyle(
                  fontSize: Get.setFontSize(14),
                  fontFamily: Get.setFontFamily(),
                  fontWeight: FontWeightX.regular,
                  color: Get.theme.textSecondary,
                  overflow: TextOverflow.ellipsis),
              noDataText: ID.noDataText.tr,
            ),
            child: child));
  }
}


 @override
  build(BuildContext context) {
    return GetBuilder<TokenActivityController>(
        id: GetKey.assetsActivityId,
        tag: tag,
        builder: (controller) {
          return controller.obx((state) => buildContent(action!),
              onLoading: !controller.hasCache
                  ? const HomeTokeListSkeletonWidget()
                  : buildContent(action!),
              onError: (error) => controller.hasCache
                  ? buildContent(action!)
                  : AppErrorWidget(onRefresh: () {
                      controller.showLoading();
                      controller.loadData();
                    }),
              onEmpty: const AppEmptyWidget());
        });
  }

  buildContent(ActivityAction action) {
    if (action == ActivityAction.send && controller.sendDataList.isEmpty) {
      return const AppEmptyWidget();
    } else if (action == ActivityAction.receive &&
        controller.receiveDataList.isEmpty) {
      return const AppEmptyWidget();
    } else if (action == ActivityAction.resources &&
        controller.resourcesDataList.isEmpty) {
      return const AppEmptyWidget();
    }
    return RefreshWidget<TokenActivityController>(
        enablePullDown: true,
        enablePullUp: false,
        controllerTag: tag,
        refreshController: controller.refreshController,
        child:
            CustomScrollView(physics: const BouncingScrollPhysics(), slivers: [
          SliverList(
              delegate: SliverChildBuilderDelegate((context, index) {
            return (controller.dataList.isNotEmpty)
                ? _itemBuilder(controller.getDataList(action)[index])
                : const SizedBox.shrink();
          }, childCount: controller.getDataList(action).length)),
          footerWidget(),
        ]));
  }

class TokenAssetsBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => TokenAssetsController());
    Get.lazyPut(() => TokenActivityController(), tag: "all");
    Get.lazyPut(() => TokenActivityController(), tag: "send");
    Get.lazyPut(() => TokenActivityController(), tag: "receive");
    Get.lazyPut(() => TokenActivityController(), tag: "resources");
  }
}

最终解决办法
,因为我页面退出有个300 毫秒的 退出动画,A页面跳转B页面,B页面按了返回键,要退出的一霎那这时候点了B页面,其实是点了A页面,又进入了B,导致Getx持有refreshController 数据紊乱,修改方法 A页面跳转B时加个isClickable 为false ,返回时等待500毫秒才能点击A

  return GestureDetector(
      onTap: () async {
        final nftController = Get.find<NftController>();

        // 防止快速点击pull_to_refresh 出现bug
        if (!nftController.isClickable.value) {
          return;
        }

        // 禁用点击事件
        nftController.isClickable.value = false;

        // 导航到详情页面
        await toDetails();

        // 等待动画结束(假设动画时间为500ms)
        await Future.delayed(const Duration(milliseconds: 500));

        // 重新启用点击事件
        nftController.isClickable.value = true;
      },

  Future toDetails() async {
    await Get.toNamed(AppRoutes.assetsDetailPage, arguments: {
      GetArgumentsKey.walletModel: controller.walletModel,
      GetArgumentsKey.addressModel: controller.addressModel,
      GetArgumentsKey.coinModel: controller.coinModel,
      GetArgumentsKey.model: model,
    });
  }

更多推荐