【Flutter】使用InteractiveViewer实现ScrollableView的放大缩小移动

Interactiveviewer是什么?

在进行Android开发时,如果我们想要实现一张图片的双指放大缩小,放大后拖动图片,就需要利用ScaleGesturedetector以及GestureDetecter来对图片进行手势监听,然后在onDraw方法中对其进行放缩以及移动的处理。但是在Flutter中,官方给我们提供了这样的一个处理类,我们只需要把想要放缩的Widget设置给Interactiveviewer,就可以实现放缩移动的效果,其内部也是使用了GestureDetector以及Listener来实现的手势监听来实现的这种效果。

// 这里是Interactiveviewer内部的build方法
 @override
  Widget build(BuildContext context) {
    Widget child;
    // ...  删除其他代码
    return Listener(
      key: _parentKey,
      onPointerSignal: _receivedPointerSignal,
      child: GestureDetector(
        behavior: HitTestBehavior.opaque, // Necessary when panning off screen.
        onScaleEnd: _onScaleEnd,
        onScaleStart: _onScaleStart,
        onScaleUpdate: _onScaleUpdate,
        child: child,
      ),
    );
  }

为什么要写这篇文章

在网上一搜Interactiveviewer,就会出来很多关于如何使用Interactiveviewer的文章,那么我为什么还要去重复的去写这么一篇文章呢?显然,如果只是简单的说下它的用法,那我这是纯属浪费大家的时间,网上的文章基本都是教大家基本的用法,但是我们在需求开发中,经常会遇到如果要求对一个列表进行放缩的时候改怎么办呢?依然简单的使用Interactiveviewer吗?显然是不行的,因为列表本身是一个可滚动的组件,如果是简单的设置给Interactiveviewer,会存在一些手势的冲突,而本篇文章,就是为了解决这些问题而写的。

正文

这里就不再去浪费时间介绍Interactiveviewer的用法以及一个普通的ImageView该怎么去放缩了,直接进入正题,如果对一个可滚动组件进行处理。

step1

简单的进行Interactiveviewer进行包裹,看看会出现什么问题?

InteractiveViewer(
        key: _key,
        scaleEnabled: true,
        boundaryMargin: margin,
        minScale: 0.5,
        maxScale: 5,
        transformationController: _controller,
        child: SizedBox.expand(
		    child: CustomScrollView(
		      controller: listController,
		      slivers: [
		        for (int i = 0; i < 9; i++)
		          SliverToBoxAdapter(
		            child: Container(
		              height: 400,
		              width: 400,
		              child: Image.asset('assets/images/test0${i + 1}.png', width: 400, height: 400,),
		            ),
		          )
		      ],
		    ),
		  ),
      )

这时会发现,咦,这不是能正常的放大缩小,放大后也能正常移动吗?确实可以,但是很快就发现当放大后,列表不能滚动到最底部或者最顶部,这是为什么呢?因为在上下滚动的时候,并不是Interactiveviewer在处理手势事件,而是列表在处理上下滚动,而滚动列表的滚动行为是ScrollController在管理,ScrollController中的listController.position.maxScrollExtent标记了列表的最大可滚动范围,当放大后,那个最大可滚动范围是不变的,所以滚动同样的距离,你当然不能看到最底部了,最顶部也是同样道理。
那该如何解决这个问题呢?

step2

解决放大后不能滚动到最底部和最顶部,这时就要借助NotificationListener去监听OverscrollNotification事件了,当监听到列表滚动到边界时,获取越界滚动值,手动处理列表的滑动。具体代码如下:

if (notification is OverscrollNotification) {
          if((notification.metrics.axisDirection == AxisDirection.up
              || notification.metrics.axisDirection == AxisDirection.down)) {
              // 判断如果是越界滚动,并且是上下滚动时
               // 注意这个controller是Interactiveviewer的TransformationController
               // 获取Interactiveviewer上下滑动的距离
            var row12 = _controller.value.row1[3]; 
            var temp = notification.dragDetails?.delta.dy ?? 0.0;  // 获取越界手势间距
            var value = _controller.value.clone();
            // 此处的_key 是设置给Interactiveviewer的GlobalKey,主要是用来获取Interactiveviewer Widget的原始大小
            var height = _key.currentContext?.size?.height ?? 0; 
  
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值