防止可拖动视图离开屏幕

Preventing draggable view to go off screen

我有一个可拖动的按钮,但我不希望用户能够拖动视图,这样两侧就会被屏幕边缘截断。

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first {
            let position = touch.location(in: self.superview)

            self.center = CGPoint(x: position.x, y: position.y)

            }

        }

我这样做的方式是大量的 if / else 语句检查屏幕上允许的区域。

 let halfOfButton = CGFloat(85 / 2)
            let heightOfTopBar = CGFloat(55) + halfOfButton
            let widthOfScreen = CGFloat((self.superview?.frame.width)!) - halfOfButton
            let heightOfScreen = CGFloat((self.superview?.frame.height)!) - heightOfTopBar

            let heightOfBotBar = CGFloat((self.superview?.frame.height)! - heightOfTopBar)


            if position.x > halfOfButton && position.x < widthOfScreen {
                self.center = CGPoint(x: position.x, y: position.y)

            } else {
                if position.x < halfOfButton {
                self.center = CGPoint(x: halfOfButton, y: position.y)
                } else {
                      self.center = CGPoint(x: widthOfScreen, y: position.y)
                }
            }

            if position.y > heightOfTopBar && position.y < heightOfScreen && position.x > halfOfButton && position.x < widthOfScreen {
                self.center = CGPoint(x: position.x, y: position.y)

            } else {
                if position.y < heightOfTopBar {
                    self.center = CGPoint(x: position.x, y: heightOfTopBar)
                } else {
                    self.center = CGPoint(x: position.x, y: heightOfScreen)
                }
            }
        }

有没有更好的方法来完成这个?上面的代码甚至还不能完全工作。它在我说 "if the Y is okay, then just allow the center of your touch to be the center of the button" 的逻辑上有很多缺陷,但它会覆盖我在 X 中编写的代码,即使 Y 可能没问题,但 X 却不行。

我可以用这种方式从逻辑上解决这个问题,但肯定有更好的方法吗?

尝试这样的事情:

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
    let position = touch.location(in: self.superview)

    var x:CGFloat = position.x
    var y:CGFloat = position.y

    let parentWidth = button.superView!.frame.size.width
    let parentHeight = button.superView!.frame.size.height

    let width = button.frame.size.width / 2
    let height = button.frame.size.height / 2

    x = max(width, x)
    x = min(x, parentWidth - width)

    y = max(height, y)
    y = min(y, parentHeight - height)



    self.center = CGPoint(x: x, y: y)

}

}

我前段时间处理过这个问题,用这个方法解决了。

首先,考虑到按钮的大小,并且不想剪掉它的一部分,我创建了一个视图(在本例中,我们称它为 containerView),它放置在您选择的区域上方希望按钮出现在其中。此视图需要从父视图中减少其边距,以便其顶部和底部边距为按钮高度的一半,并且其前缘和后缘为按钮宽度的一半。

有了这个设置,现在用一个内置函数来包含它的移动就变得相当简单了,这个函数在没有 if 语句的情况下提供了更好的性能。

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesMoved(touches, with: event)

    guard let touch = touches.first else {
        return
    }

    let location = touch.location(in: containerView)

    if containerView.point(inside: location, with: event) {
        button.center = location
    }
}

现在,根据您使用的坐标系,使用此技术可能无法将按钮正确定位在您想要的位置。如果发生这种情况,您应该能够通过在将位置值分配给 button.center 属性 之前修改位置值来解决它。

修改应该是根据您的前导和上边距将其右移或下移。理想情况下,您会为此使用故事板约束,然后您可以 link 到您的控制器,允许您直接获取这些值进行调整。