iOS 用UIPanGestureRecognizer实现单手指点击拖动缩放
图1-2
UIPinchGestureRecognizer捏合手势用来缩放有一定的局限性,为此添加了用UIPanGestureRecognizer拖拽手势来实现缩放,代码的主要部分就是进行scale值的计算,不同象限的操作不同,这里的象限指的数学的象限1-1图示:
图1-2
iOS 手机中的坐标系如图1-3:
图1-3
当我们触发拖动事件时需要以began(sender.state)的点为原点(即屏幕刚刚接收到点击事件的point),来创建一个坐标系,手指移动位置点用来计算;如图1-4:
图1-4
如上图所示,红色点表示拖拽事件(state == .degan)刚刚开始的点,蓝色的点表示四个象限中手指移动的点的位置;
结合图1-1最终我们依据计算的图如下:
### 具体的计算步骤为
-
计算蓝点和红点x和y的偏移量,即:
offsetX = x1 - x0
offsetY = y1 -y0 -
计算x轴方向和y轴方向的scale值:
size指的是View的大小:
scaleY = (size.height + offsetY) / size.height
scaleX = (size.width + offsetX) / size.width -
因为手势是持续性滑动,offsetX、offsetY一直在不停的变化,无法有一只均匀大小变化的值,即x1,y1的值根据你手势的变化导致他们的变化不是一个均匀大小变化的值(不是匀加速或匀减速);这样的scale直接拿过来用会出现UIView的大小无法控制的跳动,忽大忽小。
为了解决上面的问题,我采用了平均值,(scaleY + scaleX)/2,这样就不会出现跳动的问题了;
代码
// 拖动放大
let panGap3 = UIPanGestureRecognizer(target: self, action: #selector(panScaleHandle(_:)))
bottomRightView.addGestureRecognizer(panGap3)
bottomRightView.isUserInteractionEnabled = true
@objc func panScaleHandle(_ sender: UIPanGestureRecognizer) {
let location = sender.location(in: self)
switch sender.state {
case .began:
panScaleBeginPoint = location
print("began")
break
case .changed:
let size = self.frame.size
var scale: CGFloat = 0.0
let changeX = location.x - panScaleBeginPoint.x
let changeY = location.y - panScaleBeginPoint.y
// 放大
//第四象限
// if location.x > panScaleBeginPoint.x || location.y > panScaleBeginPoint.y {
// scale = (size.width + changeX) / size.width / 2
// scale += (size.height + changeY) / size.height / 2
// }
// //第一象限 第二象限 第三象限
// if location.x < panScaleBeginPoint.x || location.y < panScaleBeginPoint.y {
scale = (size.height + changeY) / size.height / 2
scale += (size.width + changeX) / size.width / 2
// }
if size.width * scale < minWidth {
scale = 1.0
}
self.transform = self.transform.scaledBy(x: scale, y: scale)
default:
break
}
其中注释的代码忽略不计,刚开始想根据不同象限来判断放大缩小,添加了象限的判断,但当使用平均值来计算scale就省掉了,效果也是👌的!
有更好的方法的小伙伴欢迎👏留言讨论。 文章有用的话点赞👍,关注来一波,嘻嘻😄!!!