写点什么

Flutter- 可以缩放拖拽的图片 (1),android 最新开发语言

用户头像
Android架构
关注
发布于: 10 小时前

3.当图片是那种长宽相差很大的时候,进行缩放的时候,将首先沿着比较长的那边进行中心点缩放,直到图片铺满区域之后,按照 1 来执行


4.当进行缩放操作的时候,不进行移动操作


1,2,3 对应代码


Offset _getCenter(Rect destinationRect) {if (!userOffset && _center != null) {return _center;}


if (totalScale > 1.0) {if (_computeHorizontalBoundary && _co


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


mputeVerticalBoundary) {return destinationRect.center * totalScale + offset;} else if (_computeHorizontalBoundary) {//only scale Horizontalreturn Offset(destinationRect.center.dx * totalScale,destinationRect.center.dy) +Offset(offset.dx, 0.0);} else if (_computeVerticalBoundary) {//only scale Verticalreturn Offset(destinationRect.center.dx,destinationRect.center.dy * totalScale) +Offset(0.0, offset.dy);} else {return destinationRect.center;}} else {return destinationRect.center;}}


4 对应代码,当 details.scale==1.0,说明是一个移动操作,否则为了一个缩放操作


void _handleScaleUpdate(ScaleUpdateDetails details) {...var offset =((details.scale == 1.0 ? details.focalPoint : _startingOffset) -_normalizedOffset * scale);...}


获取到了图片的中心点之后,我们再根据 Scale 等到图片的整个区域


Rect _getDestinationRect(Rect destinationRect, Offset center) {final double width = destinationRect.width * totalScale;final double height = destinationRect.height * totalScale;


return Rect.fromLTWH(center.dx - width / 2.0, center.dy - height / 2.0, width, height);}

拖拽边界的计算

1.计算是否需要计算限制边界 2.如果需要将区域限制在边界内部


if (_computeHorizontalBoundary) {//move rightif (result.left >= layoutRect.left) {result = Rect.fromLTWH(0.0, result.top, result.width, result.height);_boundary.left = true;}


///move leftif (result.right <= layoutRect.right) {result = Rect.fromLTWH(layoutRect.right - result.width, result.top,result.width, result.height);_boundary.right = true;}}


if (_computeVerticalBoundary) {//move downif (result.bottom <= layoutRect.bottom) {result = Rect.fromLTWH(result.left, layoutRect.bottom - result.height,result.width, result.height);_boundary.bottom = true;}


//move upif (result.top >= layoutRect.top) {result = Rect.fromLTWH(result.left, layoutRect.top, result.width, result.height);_boundary.top = true;}}


_computeHorizontalBoundary =result.left <= layoutRect.left && result.right >= layoutRect.right;


_computeVerticalBoundary =result.top <= layoutRect.top && result.bottom >= layoutRect.bottom;

缩放回弹效果以及拖拽惯性效果

void _handleScaleEnd(ScaleEndDetails details) {//animate back to maxScale if gesture exceeded the maxScale specifiedif (_gestureDetails.totalScale > _gestureConfig.maxScale) {final double velocity =(_gestureDetails.totalScale - _gestureConfig.maxScale) /_gestureConfig.maxScale;


_gestureAnimation.animationScale(_gestureDetails.totalScale, _gestureConfig.maxScale, velocity);return;}


//animate back to minScale if gesture fell smaller than the minScale specifiedif (_gestureDetails.totalScale < _gestureConfig.minScale) {final double velocity =(_gestureConfig.minScale - _gestureDetails.totalScale) /_gestureConfig.minScale;


_gestureAnimation.animationScale(_gestureDetails.totalScale, _gestureConfig.minScale, velocity);return;}


if (_gestureDetails.gestureState == GestureState.pan) {// get magnitude from gesture velocityfinal double magnitude = details.velocity.pixelsPerSecond.distance;


// do a significant magnitudeif (magnitude >= minMagnitude) {final Offset direction = details.velocity.pixelsPerSecond /magnitude *_gestureConfig.inertialSpeed;


_gestureAnimation.animationOffset(_gestureDetails.offset, _gestureDetails.offset + direction);}}}


唯一注意的是 Scale 的回弹动画将以最后的缩放中心点为中心进行缩放,这样缩放动画才看起来舒服一些


//true: user zoom/pan//false: animationfinal bool userOffset;Offset _getCenter(Rect destinationRect) {if (!userOffset && _center != null) {return _center;}

在 PageView 里面缩放拖拽

用法

1.使用ExtendedImageGesturePageView展示图片


2.设置 GestureConfig 的 inPageView 为 Ture


GestureConfig 参数说明


实现过程

手势冲突

这个场景需要关注的是手势的冲突问题,PageView 里面是有水平或者垂直的手势的,会跟 onScaleStart/onScaleUpdate/onScaleEnd 有冲突。


最开始想的是手势应该有冒泡,是不是可以我监听到了之后,不像上冒泡,这样可以阻止 PageView 里面的滑动行为,最后结论是没有方法能阻止冒泡。


关于手势,大家可以看看拉面小姐姐关于手势的文章,神奇的竞技场概念。。


既然不能阻止手势冒泡,那么我就直接不让你能滚动了,然后全部的手势都交给我,我来处理。


首先我看了下 PageView 关于滚动的源码,直接指向最终 ScrollableState 里面的代码,在 setCanDrag 方法里面根据是否可以 Drag,准备了水平/垂直的手势。


把 ScrollableState 里面关于水平垂直滚动处理的代码拿出来,我创建了一个属于 extended_image 专门的 extended_image_gesture_page_view,属性跟 PageView 一样只是没法设置 physics,因为强制设置为了 NeverScrollableScrollPhysics


Widget result = PageView.custom(scrollDirection: widget.scrollDirection,reverse: widget.reverse,controller: widget.controller,childrenDelegate: widget.childrenDelegate,pageSnapping: widget.pageSnapping,physics: widget.physics,onPageChanged: widget.onPageChanged,key: widget.key,);


result = RawGestureDetector(gestures: _gestureRecognizers,behavior: HitTestBehavior.opaque,child: result,);


然后我们通过 RawGestureDetector 来注册_gestureRecognizers(水平/垂直的手势)。


关于_gestureRecognizers,我之前一直好奇 PageView 里面有个手 hold 的操作是怎么做到了,直到看到源码才知道这么个东西,源码真是个好东西。


void _handleDragDown(DragDownDetails details) {//print(details);_gestureAnimation.stop();assert(_drag == null);assert(_hold == null);_hold = position.hold(_disposeHold);}

到达边界滚动上下一个图片

有了之前缩放拖拽的基础,这部分就比较简单了。如果到达边界就是用默认代码去操作 PageView,否则就控制 Image 进行拖拽操作


void _handleDragUpdate(DragUpdateDetails details) {// _drag might be null if the drag activity ended and called _disposeDrag.assert(_hold == null || _drag == null);var delta = details.delta;

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Flutter-可以缩放拖拽的图片(1),android最新开发语言