Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug report] ExtendedImageSlidePage中嵌套图片或者ExtendedImageGesturePageView的问题 #683

Open
wangzhipeng-vicky opened this issue May 31, 2024 · 0 comments

Comments

@wangzhipeng-vicky
Copy link

Version

8.2.0

Platforms

Android, iOS

Device Model

小米9

flutter info

Flutter version 2.5.1

How to reproduce?

我是ExtendedImageSlidePage中嵌套ExtendedImageGesturePageView,实现的看大图的需求,就是我手往下滑动大图界面能关掉,没有问题。但是问题是:

  • 问题1:
    • 点开大图后,我把图网上滑动,手松开,滑到哪,图就在那,然后这时图也不能手势/双击缩放,底下的pageIndictor也会隐藏掉。如下面两个图
  • 问题2:大图展示后双指缩放图片很是不灵敏,及其难用。只有双击能缩放

image
image

`@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
imageDRect = Offset.zero & size;

Widget result = ExtendedImageSlidePage(
    key: slidePagekey,
    // slideAxis: SlideAxis.vertical,
    // slideType: SlideType.wholePage,

    //在滑动页面的时候根据 Offset 自定义整个页面的背景色
    slidePageBackgroundHandler: (
      Offset offset,
      Size pageSize,
    ) {
      double opacity = 0.0;
      // if (pageGestureAxis == SlideAxis.both) {
      opacity = offset.distance /
          (Offset(pageSize.width, pageSize.height).distance / 2.0);
      // } else if (pageGestureAxis == SlideAxis.horizontal) {
      //   opacity = offset.dx.abs() / (pageSize.width / 2.0);
      // } else if (pageGestureAxis == SlideAxis.vertical) {
      //   opacity = offset.dy.abs() / (pageSize.height / 2.0);
      // }
      return const Color(0x00000000)
          .withOpacity(min(1.0, max(1.0 - opacity, 0.0)));
    },

    //在滑动页面的时候根据 Offset 自定义整个页面的缩放值
    slideScaleHandler: (
      Offset offset, {
      ExtendedImageSlidePageState? state,
    }) {
      //image is ready and it's not sliding.
      if (state != null &&
          detailKeys[_currentIndex!] != null &&
          state.scale == 1.0) {
        //don't slide page if scale of image is more than 1.0
        if (state.imageGestureState!.gestureDetails!.totalScale! > 1.0) {
          return 1.0;
        }
        //or slide down into detail mode
        if (offset.dy < 0 || _imageDetailY < 0) {
          return 1.0;
        }
      }

      return null;
    },

    //在滑动页面的时候自定义 Offset
    slideOffsetHandler: (
      Offset offset, {
      ExtendedImageSlidePageState? state,
    }) {

      //image is ready and it's not sliding.
      if (state != null &&
          detailKeys[_currentIndex!] != null &&
          state.scale == 1.0) {
        //don't slide page if scale of image is more than 1.0

        if (state.imageGestureState!.gestureDetails!.totalScale! > 1.0) {
          return Offset.zero;
        }

        //or slide down into detail mode
        if (offset.dy < 0 || _imageDetailY < 0) {
          _imageDetailY += offset.dy;

          // print(offset.dy);
          _imageDetailY = max(
              -detailKeys[_currentIndex!]!.maxImageDetailY, _imageDetailY);
          rebuildDetail.sink.add(_imageDetailY);
          return Offset.zero;
        }

        if (_imageDetailY != 0) {
          _imageDetailY = 0;
          _showSwiper = true;
          rebuildSwiper.add(_showSwiper);
          rebuildDetail.sink.add(_imageDetailY);
        }
      }
      return null;
    },

    //滑动页面结束的时候计算是否需要 pop 页面
    slideEndHandler: (
      Offset offset, {
      ExtendedImageSlidePageState? state,
      ScaleEndDetails? details,
    }) {

      if (_imageDetailY != 0 && state!.scale == 1) {
        if (!_slideEndAnimationController.isAnimating) {

// get magnitude from gesture velocity
final double magnitude =
details!.velocity.pixelsPerSecond.distance;

          // do a significant magnitude

          if (magnitude.greaterThanOrEqualTo(minMagnitude)) {
            final Offset direction =
                details.velocity.pixelsPerSecond / magnitude * 1000;

            _slideEndAnimation =
                _slideEndAnimationController.drive(Tween<double>(
              begin: _imageDetailY,
              end: (_imageDetailY + direction.dy)
                  .clamp(-detailKeys[_currentIndex!]!.maxImageDetailY, 0.0),
            ));
            _slideEndAnimationController.reset();
            _slideEndAnimationController.forward();
          }
        }
        return false;
      }

      return null;
    },

    //滑动页面的回调,你可以在这里改变页面上其他元素的状态
    onSlidingPage: (ExtendedImageSlidePageState state) {

      ///you can change other widgets' state on page as you want
      ///base on offset/isSliding etc
      //var offset= state.offset;
      final bool showSwiper = !state.isSliding;
      if (showSwiper != _showSwiper) {
        // do not setState directly here, the image state will change,
        // you should only notify the widgets which are needed to change
        // setState(() {
        // _showSwiper = showSwiper;
        // });

        _showSwiper = showSwiper;
        rebuildSwiper.add(_showSwiper);
      }
    },

    child: Material(
      /// if you use ExtendedImageSlidePage and slideType =SlideType.onlyImage,
      /// make sure your page is transparent background
      color: Colors.transparent,
      // color: Colors.redAccent,

      shadowColor: Colors.transparent,

      child: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          ExtendedImageGesturePageView.builder(
            controller: ExtendedPageController(
              initialPage: widget.index!,
              // pageSpacing: 32,//两个图之间的边距  越大,在A图的右边就能看见B图  2024年5月31日11:18:28
              shouldIgnorePointerWhenScrolling: true,
            ),
            scrollDirection: Axis.horizontal,
            // physics: const BouncingScrollPhysics(),
            //定义PageView的滚动行为
            canScrollPage: (GestureDetails? gestureDetails) {
              return _imageDetailY >= 0;
              //return (gestureDetails?.totalScale ?? 1.0) <= 1.0;
            },
            itemBuilder: (BuildContext context, int index) {
              int imageTyep = widget.pics![index].type;

              late Widget image;

              Map extendParams = {
                "fit": BoxFit.contain,
                "enableSlideOutPage": true,
                "mode": ExtendedImageMode.gesture,
                // 手势配置的回调(图片加载完成时).你可以根据图片的信息比如宽高,来初始化
                "initGestureConfigHandler": (ExtendedImageState state) {
                  double? initialScale = 1.0;

                  //暂时不要这个了   直接初始默认就是1  而不要计算的,因为对于大图会出现一开始是方法的模式 2024年5月31日10:26:11
                  if (state.extendedImageInfo != null) {
                    initialScale = initScale(
                        size: size,
                        initialScale: initialScale,
                        imageSize: Size(
                            state.extendedImageInfo!.image.width.toDouble(),
                            state.extendedImageInfo!.image.height
                                .toDouble()));
                  }
                  return GestureConfig(
                    inPageView: true,
                    // initialScale: initialScale!,
                    initialScale: 1,
                    // maxScale: max(initialScale, 5.0),
                    // animationMaxScale: max(initialScale, 5.0),
                    initialAlignment: InitialAlignment.center,
                    minScale: 1.0,
                    //you can cache gesture state even though page view page change.
                    //remember call clearGestureDetailsCache() method at the right time.(for example,this page dispose)
                    cacheGesture: true,
                  );
                },

                "onDoubleTap": (ExtendedImageGestureState state) {
                  ///you can use define pointerDownPosition as you can,
                  ///default value is double tap pointer down postion.
                  final Offset? pointerDownPosition =
                      state.pointerDownPosition;
                  final double? begin = state.gestureDetails!.totalScale;
                  double end;

                  //remove old
                  _doubleClickAnimation
                      ?.removeListener(_doubleClickAnimationListener);

                  //stop pre
                  _doubleClickAnimationController.stop();

                  //reset to use
                  _doubleClickAnimationController.reset();

                  if (begin == doubleTapScales[0]) {
                    end = doubleTapScales[1];
                  } else {
                    end = doubleTapScales[0];
                  }

                  _doubleClickAnimationListener = () {
                    //print(_animation.value);
                    state.handleDoubleTap(
                        scale: _doubleClickAnimation!.value,
                        doubleTapPosition: pointerDownPosition);
                  };
                  _doubleClickAnimation = _doubleClickAnimationController
                      .drive(Tween<double>(begin: begin, end: end));

                  _doubleClickAnimation!
                      .addListener(_doubleClickAnimationListener);

                  _doubleClickAnimationController.forward();
                },
              };

              if (imageTyep == 0 || imageTyep == 60) {
                //网络图

                final String? originPath = widget.pics![index].originPath;
                String? demoPath = widget.pics![index].demoPath;
                String? prePath = widget.pics![index].preViewDemo;
                String item;
                if (imageTyep == 60) {
                  item = prePath ?? demoPath!;
                } else {
                  item = originPath!;
                }

                image = createNetworkImage(
                  item,
                  index,
                  extendParams: extendParams,
                  // fit: BoxFit.contain,
                  // enableSlideOutPage: true,
                  // mode: ExtendedImageMode.gesture,

                  loadStateChanged: (ExtendedImageState state) {
                    if (state.extendedImageLoadState ==
                        LoadState.completed) {
                      final Rect imageDRect = getDestinationRect(
                        rect: Offset.zero & size,
                        inputSize: Size(
                          state.extendedImageInfo!.image.width.toDouble(),
                          state.extendedImageInfo!.image.height.toDouble(),
                        ),
                        fit: BoxFit.contain,
                      );

                      detailKeys[index] ??= ImageDetailInfo(
                        imageDRect: imageDRect,
                        pageSize: size,
                        imageInfo: state.extendedImageInfo!,
                      );

                      final ImageDetailInfo? imageDetailInfo =
                          detailKeys[index];

                      return StreamBuilder<double>(
                        builder: (BuildContext context,
                            AsyncSnapshot<double> data) {
                          return ExtendedImageGesture(
                            state,
                            canScaleImage: (_) => _imageDetailY == 0,
                            imageBuilder: (Widget image) {
                              return Stack(
                                children: <Widget>[
                                  Positioned.fill(
                                    top: _imageDetailY,
                                    bottom: -_imageDetailY,
                                    child: image,
                                  ),
                                  Positioned(
                                    left: 0.0,
                                    right: 0.0,
                                    top: imageDetailInfo!.imageBottom +
                                        _imageDetailY,
                                    child: Opacity(
                                      opacity: _imageDetailY == 0
                                          ? 0
                                          : min(
                                              1,
                                              _imageDetailY.abs() /
                                                  (imageDetailInfo
                                                          .maxImageDetailY /
                                                      4.0),
                                            ),
                                    ),
                                  ),
                                ],
                              );
                            },
                          );
                        },
                        initialData: _imageDetailY,
                        stream: rebuildDetail.stream,
                      );
                    } else if (state.extendedImageLoadState ==
                        LoadState.loading) {
                      return Center(
                        child: Image.asset(
                          "assets/images/loading.gif",
                          width: 40,
                          height: 40,
                        ),
                      );
                    } else if (state.extendedImageLoadState ==
                        LoadState.failed) {
                      return GestureDetector(
                        child: /*Container(
                color: const Color(0xFFF3F4F5),
                child:*/
                            Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                crossAxisAlignment:
                                    CrossAxisAlignment.center,
                                children: [
                              Image.asset(
                                "assets/images/img_load_failed.png",
                                // "assets/images/loading.gif",
                                width: 40,
                                height: 40,
                              ),
                              const Padding(
                                padding: EdgeInsets.only(
                                    left: 3, top: 15, right: 3),
                                child: Text(
                                  "加载失败,点击重试",
                                  style: TextStyle(
                                      fontSize: 15,
                                      color: Color(0XFF999999)),
                                  textAlign: TextAlign.center,
                                ),
                              )
                            ]),
                        // ),
                        onTap: () {
                          state.reLoadImage();
                        },
                      );
                    }
                    return null;
                  },
                );
              } else if (imageTyep == 1 || imageTyep == 61) {
                image = createFileWithWechatPicker(
                  widget.pics![index].entity!,
                  extendParams: extendParams,
                );

                // tag = widget.pics![index].tag;
              }

              if (index < min(9, widget.pics!.length)) {
                image = HeroWidget(
                  tag: widget.pics![index].tag,
                  slideType: SlideType.onlyImage,
                  slidePagekey: slidePagekey,
                  child: image,
                );
              }

              image = GestureDetector(
                child: image,
                onTap: () {
                  if (_imageDetailY != 0) {
                    _imageDetailY = 0;
                    rebuildDetail.sink.add(_imageDetailY);
                  } else {
                    slidePagekey.currentState!.popPage();
                    Navigator.pop(context);
                  }
                },
              );

              return  image;
            },

            itemCount: widget.pics!.length,

            onPageChanged: (int index) {
              _currentIndex = index;
              rebuildIndex.add(index);
              if (_imageDetailY != 0) {
                _imageDetailY = 0;
                rebuildDetail.sink.add(_imageDetailY);
              }
              _showSwiper = true;
              rebuildSwiper.add(_showSwiper);
              _preloadImage(index - 1);
              _preloadImage(index + 1);
            },
          ),
          Visibility(
              visible: !(widget.isOnlyPreview && widget.pics!.length == 1),
              child: StreamBuilder<bool>(
                //负责根据不同状态创建对应ui的方法实现
                builder: (BuildContext c, AsyncSnapshot<bool> d) {
                  if (d.data == null || !d.data!) {
                    return Container();
                  }

                  return Positioned(
                    bottom: 0.0,
                    left: 0.0,
                    right: 0.0,
                    child: MySwiperPlugin(widget.pics, _currentIndex,
                        rebuildIndex, widget.operateMenu),
                  );
                },
                initialData: true, //默认初始化数据
                stream: rebuildSwiper
                    .stream, //stream事件流对象   rebuildSwiper.stream获取Stream用作事件监听
              ))
        ],
      ),
    ));
return  result;

}`

Logs

No response

Example code (optional)

No response

Contact

[email protected]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant