写点什么

Flutter- 可以缩放拖拽的图片,安卓内存优化管理器

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

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;


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


_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;


if (extendedImageGestureState != null) {var gestureDetails = extendedImageGestureState.gestureDetails;if (gestureDetails != null) {if (gestureDetails.movePage(delta)) {_drag?.update(details);} else {extendedImageGestureState.gestureDetails = GestureDetails(offset: gestureDetails.offset +delta * extendedImageGestureState.imageGestureConfig.speed,totalScale: gestureDetails.totalScale,gestureDetails: gestureDetails);}} else {_drag?.update(details);}} else {_drag?.update(details);}}

拖拽惯性效果

在 DragEnd 的时候,我们需要注意下处理下惯性。当图片是放大状态而且水平或者垂直能够滑动的时候,我们需要_drag 停止下来,以防止直接滑动到上一个或者下一个图片DragEndDetails(primaryVelocity: 0.0),并且根据惯性让图片在范围内继续惯性滑动。


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


var temp = details;


if (extendedImageGestureState != null) {var gestureDetails = extendedImageGestureState.gestureDetails;


if (gestureDetails != null && gestureDetails.computeHorizontalBoundary ||gestureDetails.computeVerticalBoundary) {//stoptemp = DragEndDetails(primaryVelocity: 0.0);


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


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


if (widget.scrollDirection == Axis.horizontal) {direction = Offset(direction.dx, 0.0);

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Flutter-可以缩放拖拽的图片,安卓内存优化管理器