如何将可拖动的 UIView 限制在特定范围内
Posted
技术标签:
【中文标题】如何将可拖动的 UIView 限制在特定范围内【英文标题】:How to restrict a draggable UIView to specific bounds 【发布时间】:2016-06-02 14:29:55 【问题描述】:我有一个 UIImageView
,我通过一个名为 DraggableImageView2
的自定义类将其设为 Draggable。然后该类在带有图像的UIViewController
中实例化,并且可以在UIView
中拖动。问题是我想限制UIImageView
在拖动时不要越过特定边界。这是我当前的代码:
import UIKit
class DraggableImageView2: UIImageView, UIGestureRecognizerDelegate
var dragStartPositionRelativeToCenter : CGPoint?
var dragGesture: UIGestureRecognizer!
var zoomGesture: UIGestureRecognizer!
var lastKnownCenterX: CGFloat = 0.0
var lastKnownCenterY: CGFloat = 0.0
required init?(coder aDecoder: NSCoder)
super.init(coder: aDecoder)
self.initializeGestures()
override init(image: UIImage?)
super.init(image: image)
self.initializeGestures()
override init(frame: CGRect)
super.init(frame: frame)
self.initializeGestures()
func initializeGestures()
self.userInteractionEnabled = true
self.multipleTouchEnabled = true
dragGesture = UIPanGestureRecognizer(target: self, action: #selector(DraggableImageView.handlePan(_:)))
self.addGestureRecognizer(dragGesture)
func handlePan(recognizer: UIPanGestureRecognizer!)
Scripts.log("PAN >>> MOVE ACTIVATED")
if recognizer.state == UIGestureRecognizerState.Began
let locationInView = recognizer.locationInView(superview)
dragStartPositionRelativeToCenter = CGPoint(x: locationInView.x - center.x, y: locationInView.y - center.y)
return
if recognizer.state == UIGestureRecognizerState.Ended
dragStartPositionRelativeToCenter = nil
return
let locationInView = recognizer.locationInView(superview)
Scripts.log("PAN LOCATION >>> X = \(self.frame.origin.x) | Y = \(self.frame.origin.y) | LX = \(locationInView.x) | LY = \(locationInView.y) | DX = \(self.dragStartPositionRelativeToCenter!.x) | DY = \(self.dragStartPositionRelativeToCenter!.y)")
let xDragMin: CGFloat = 1.0
let yDragMin: CGFloat = 1.0
let xDragMax: CGFloat = kDEVICE_WIDTH - self.frame.size.width - 1.0
let yDragMax: CGFloat = kDEVICE_WIDTH - self.frame.size.height - 1.0
var newCenterX: CGFloat = locationInView.x - self.dragStartPositionRelativeToCenter!.x
var newCenterY: CGFloat = locationInView.y - self.dragStartPositionRelativeToCenter!.y
if self.frame.origin.x < xDragMin
Scripts.log("PAN LOCATION >>> X MIN PAST BOUNDS")
newCenterX = lastKnownCenterX
if self.frame.origin.y < yDragMin
Scripts.log("PAN LOCATION >>> Y MIN PAST BOUNDS")
newCenterY = lastKnownCenterY
if self.frame.origin.x > xDragMax
Scripts.log("PAN LOCATION >>> X MAX PAST BOUNDS")
if self.frame.origin.y > yDragMax
Scripts.log("PAN LOCATION >>> Y MAX PAST BOUNDS")
UIView.animateWithDuration(0.1)
self.center = CGPoint(x: newCenterX,
y: newCenterY)
lastKnownCenterX = newCenterX
lastKnownCenterY = newCenterY
func handlePinch(recognizer: UIPinchGestureRecognizer!)
Scripts.log("PINCH >>> ZOOM ACTIVATED")
//self.bringSubviewToFront(recognizer.view!)
recognizer.view?.transform = CGAffineTransformScale((recognizer.view?.transform)!, recognizer.scale, recognizer.scale)
recognizer.scale = 1
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool
Scripts.log("shouldRecognizeSimultaneouslyWithGestureRecognizer WAS CALLED")
return true
我才开始研究xDragMin
和yDragMin
部分。当它小于 xDragMin
时,一切都可以阻止它,但是由于某种奇怪的原因,当你试图拖出它时,它会冻结在那个 X 点。 yDragMin
也一样,如果达到最小值,它会按原样停止,但不能拖出 Y 点。
【问题讨论】:
您可以尝试记录lastKnownCenterX
和lastKnownCenterY
吗?如果这些值以某种方式设置为小于 xDragMin
或 xDragY
的值,那么您的视图框架肯定会卡在该位置。
@KyleParent 刚刚尝试记录它。不,似乎最后一个已知点的设置小于 Drag Min Points。这是一个冻结的示例输出: LAST KNOWN LOCATION :PRE: >>> X = 56.75 | Y = 301.75 最后一个已知位置 :POST: >>> X = 56.75 | Y = 301.75
当lastKnownCenterX
为56.75 时,视图的frame.origin.x
是多少?
啊,所以我的怀疑是正确的 - 不知何故,您的视图被允许通过 xDragMin
阈值。一旦发生这种情况,您将始终点击第一个条件并设置newCenterX = lastKnownCenterX
,其中lastKnownCenterX
已经离左边太远了。我建议重新审视用于计算 newCenterX
和 newCenterX
的逻辑。不应该是var newCenterX: CGFloat = locationInView.x + self.dragStartPositionRelativeToCenter!.x
吗?
@KyleParent 这不起作用,但我认为您的线索和建议帮助我确定了我认为问题所在,尤其是在添加更多日志之后。我认为的问题是这种逻辑“如果 self.frame.origin.x
【参考方案1】:
所以经过更多的挖掘和玩耍之后,我似乎已经能够解决我自己的问题,至少对于 X Bounds Min 而言。这是我所做的:
(1) 添加了这些新变量
var isWithinXBounds: Bool = true
var lastKnownLX: CGFloat = 0.0
(2) 以“if self.frame.origin.x
if self.frame.origin.x < xDragMin
Scripts.log("PAN LOCATION >>> X MIN PAST BOUNDS")
self.isWithinXBounds = false
//If TOUCH still moving in negative direction
if locationInView.x - lastKnownLX < 0
newCenterX = lastKnownCenterX
else
self.isWithinXBounds = true
(3) 下面是根据 BOOL 值解锁 UIImageView 的条件:
if isWithinXBounds
lastKnownCenterX = newCenterX
lastKnownLX = locationInView.x
【讨论】:
以上是关于如何将可拖动的 UIView 限制在特定范围内的主要内容,如果未能解决你的问题,请参考以下文章
ios -- 如何限制 CAEmitter 粒子轨迹的范围?