xuelongqy / flutter_easy_refresh

A flutter widget that provides pull-down refresh and pull-up load.
https://xuelongqy.github.io/flutter_easy_refresh/
MIT License
3.89k stars 633 forks source link

当SecondaryBuilderHeader和NestedScrollView整合使用的时候,无法关闭已经打开了的二楼页面 #853

Open liuhll opened 1 month ago

liuhll commented 1 month ago

版本为: easy_refresh: ^3.4.0 出现的现象: 打开二楼后,页面往下滑动后,二楼的页面并没有被关闭,从主页面往上滑动的时候,并未出现再次刷新的情况,如下所示。并且打开二楼后,发现日志就一直在输出 mode state: IndicatorMode.secondaryOpen, page: Opacity-[GlobalKey#554a6](opacity: 1.0),感觉发生bug的场景跟这个应该是差不多的 #713 WeChat_20240731160035 00h00m00s-00h00m11s

核心代码如下所示:

  _buildMain(MediaQueryData mediaQuery, Size size) {
    return EasyRefresh.builder(
        scrollController: _scrollController,
        controller: _refreshController,
        header: SecondaryBuilderHeader(
          header: buildClassicHeader(
            backgroundColor: HiColors.home_bg,
            mainAxisAlignment: MainAxisAlignment.end,
            position: IndicatorPosition.locator,
            clipBehavior: Clip.none,
            safeArea: true,
            clamping: true,
          ),
          secondaryTriggerOffset: 120,
          secondaryDimension: size.height,
          listenable: _listenable,
          builder: (context, state, header) {
            final mode = state.mode;
            final offset = state.offset;
            final actualSecondaryTriggerOffset =
                state.actualSecondaryTriggerOffset!;
            final actualTriggerOffset = state.actualTriggerOffset;
            double scale = 1;
            if (state.offset > state.actualTriggerOffset) {
              scale = math.max(
                  0.0,
                  (actualSecondaryTriggerOffset - offset) /
                      (actualSecondaryTriggerOffset - actualTriggerOffset));
            }
            return Stack(
              clipBehavior: Clip.none,
              children: [
                SizedBox(
                  height: state.offset,
                  width: double.infinity,
                ),
                Positioned(
                  bottom: 0,
                  left: 0,
                  right: 0,
                  child: SizedBox(
                    height: size.height,
                    width: double.infinity,
                    child: Builder(
                      builder: (context) {
                        Widget secondaryPage = Opacity(
                            key: _secondaryPageKey,
                            opacity: 1 - scale,
                            child: const Stack(
                              children: [
                                Center(
                                  child: Text('测试二楼页面'),
                                )
                              ],
                            ));

                        if (mode == IndicatorMode.secondaryOpen ||
                            mode == IndicatorMode.secondaryClosing) {
                          logger.d(
                            'mode state: $mode, page: $secondaryPage',
                          );
                          WidgetsBinding.instance.addPostFrameCallback((_) {
                            configProvider.openHomeSecondaryPage = true;
                          });
                          return PopScope(
                            canPop: false,
                            onPopInvoked: (_) {
                              _refreshController.closeHeaderSecondary();
                            },
                            child: secondaryPage,
                          );
                        }
                        return secondaryPage;
                      },
                    ),
                  ),
                ),
                Positioned(
                  bottom: 24,
                  left: 0,
                  right: 0,
                  child: Center(
                    child: AnimatedOpacity(
                      opacity: mode == IndicatorMode.secondaryArmed ? 1 : 0,
                      duration: const Duration(milliseconds: 200),
                      child: Text('打开维权日历'),
                    ),
                  ),
                ),
                Opacity(
                  opacity: (mode == IndicatorMode.secondaryReady ||
                          mode == IndicatorMode.secondaryOpen ||
                          mode == IndicatorMode.secondaryClosing)
                      ? 0
                      : scale,
                  child: header.build(context, state),
                ),
              ],
            );
          },
        ),
        childBuilder: (context, physics) {
          return _buildBody(context, physics);
        },
        onRefresh: () async {
          await Future.delayed(const Duration(seconds: 2));
          if (!mounted) {
            return;
          }
          _refreshController.finishRefresh();
          _refreshController.resetFooter();
        });

  _buildBody(BuildContext context, ScrollPhysics physics) {
    return NestedScrollView(
        physics: physics,
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return [
            const HeaderLocator.sliver(
              clearExtent: false,
            ),
            ValueListenableBuilder<IndicatorState?>(
              valueListenable: _listenable,
              builder: (context, state, child) {
                double scale = 1;
                if (state != null) {
                  if (state.offset > state.actualTriggerOffset) {
                    scale = math.max(
                        0.0,
                        (state.actualSecondaryTriggerOffset! - state.offset) /
                            (state.actualSecondaryTriggerOffset! -
                                state.actualTriggerOffset));
                  }
                }
                return SliverOpacity(
                  opacity: scale,
                  sliver: _buildAppBar(),
                );
              },
            ),
            // _buildAppBar(),
            _topBoxContainer(),
            _orderActionBoxContainer(),
            _briefReportContainer(),
            _secondaryActionBoxContainer(),
            _bannerBoxContainer(),
            _recommendedLawyerContainer(),
            _specialtyActionContainer(),
            _tabBarContainer(),
          ];
        },
        controller: _scrollController,
        body: _buildTabView(context, physics));

  }
  }

/// 构建ClassicHeade
ClassicHeader buildClassicHeader({
  TextStyle? loadingTextStyle,
  String noMoreText = "没有更多数据了",
  IndicatorPosition position = IndicatorPosition.above,
  clipBehavior = Clip.hardEdge,
  Color? backgroundColor,
  bool hasError = false,
  bool clamping = false,
  bool safeArea = true,
  MainAxisAlignment mainAxisAlignment = MainAxisAlignment.center,
}) {
  DateTime now = DateTime.now();
  String formattedTime = DateFormat('HH:mm:ss').format(now);
  TextStyle defaultLoadingTextStyle = loadingTextStyle ??
      TextStyle(
          color: Colors.black.withOpacity(0.4),
          fontSize: 12.px,
          fontWeight: FontWeight.w400,
          fontFamily: 'PingFang SC');
  return ClassicHeader(
      backgroundColor: backgroundColor,
      safeArea: safeArea,
      clipBehavior: clipBehavior,
      clamping: clamping,
      position: position,
      mainAxisAlignment: mainAxisAlignment,
      dragText: '下拉刷新',
      armedText: '释放开始',
      readyText: '正在刷新...',
      processingText: '正在刷新...',
      processedText: '刷新完成',
      failedText: '刷新失败',
      textStyle: defaultLoadingTextStyle,
      messageStyle: defaultLoadingTextStyle,
      noMoreText: noMoreText,
      messageText: '更新于 $formattedTime',
      pullIconBuilder: (context, state, animation) {
        return _buildPullIcon(context, state, animation, hasError);
      });
}
liuhll commented 1 month ago

不知道是因为我哪里没有配置对,还是easy_refresh本身存在的bug,麻烦大佬帮忙看一下,非常感谢

virtuosyo commented 4 weeks ago

一样的问题 有解决吗