如何使用 UIPanGestureRecognizer 设置拖动控件的边界?

Posted

技术标签:

【中文标题】如何使用 UIPanGestureRecognizer 设置拖动控件的边界?【英文标题】:How to set boundaries of dragging control using UIPanGestureRecognizer? 【发布时间】:2019-04-03 06:33:30 【问题描述】:

我有一个视图,我在其中添加一个标签,然后我尝试使用 PanGesture 设置移动标签的边界。以下是我的代码:

@objc func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) 
    if gestureRecognizer.state == .began || gestureRecognizer.state == .changed 
        let translation = gestureRecognizer.translation(in: self)
        if let view = gestureRecognizer.view 

            if (view.frame.origin.x + translation.x >= 0) && (view.frame.origin.y + translation.y >= 0) && (view.frame.origin.x + translation.x <= view.frame.width) && (view.frame.origin.y + translation.y <= view.frame.height)
            
                view.center = CGPoint(x:view.center.x + translation.x,
                                       y:view.center.y + translation.y)
            
        
        gestureRecognizer.setTranslation(CGPoint.zero, in: self)
    


我参考了这个答案:https://***.com/a/49008808/9970928

但它不起作用,谁能告诉我在这种情况下缺少什么?

【问题讨论】:

@dahiya_boy 是的,我正在设置主视图的边界,这里的视图是我在主视图中添加的 UILabel。现在标签不应该超出主视图。 你必须在标签上设置边界而不是视图。 不,@dahiya_boy 这里的视图是标签。所以我认为应该有一些逻辑来检查主视图边界。 你需要正确阅读你的代码并且必须调试,因为你不知道你在做什么。您刚刚复制并粘贴了代码。 @dahiya_boy 在解决方案下工作。谢谢 【参考方案1】:

代码不是最直观的,但假设其他一切正常,问题是它只超出了右侧和底部的界限。看看你的情况:

(view.frame.origin.x + translation.x <= view.frame.width)
(view.frame.origin.y + translation.y <= view.frame.height)

所以它说原点可能不会大于边界的大小你想要做的是检查内部视图的最大值:

(view.frame.maxX + translation.x <= view.frame.width)
(view.frame.maxY + translation.y <= view.frame.height)

但此过程通常可能会产生问题。想象一下,用户非常快速地向右滑动。并且最大的center.x 可以是100。当前center.x50,用户将其拖到一个框架中到200。您的条件将失败,您的标签将保留在 50 而不是 100。我会去限制框架。

应该执行以下操作:

func clampFrame(_ frame: CGRect, inBounds bounds: CGRect) -> CGRect 
    let center: CGPoint = CGPoint(x: max(bounds.minX + frame.width*0.5, min(frame.midX, bounds.maxX - frame.width*0.5)),
                                  y: max(bounds.minY + frame.height*0.5, min(frame.midY, bounds.maxY - frame.height*0.5)))
    return CGRect(x: center.x-frame.width*0.5, y: center.y-frame.height*0.5, width: frame.width, height: frame.height)


func moveFrame(_ frame: CGRect, by translation: CGPoint, constrainedTo bounds: CGRect) -> CGRect 
    var newFrame = frame
    newFrame.origin.x += translation.x
    newFrame.origin.y += translation.y
    return clampFrame(newFrame, inBounds: bounds)

使用“翻译”程序可能还有其他问题。我会去寻找一个可以看到的位置。请参阅以下工作示例:

class ViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()

        let myView = MyView(frame: CGRect(x: 100.0, y: 100.0, width: 200.0, height: 200.0))
        myView.backgroundColor = UIColor.green
        view.addSubview(myView)
        let label = UILabel(frame: .zero)
        label.backgroundColor = UIColor.blue.withAlphaComponent(0.2)
        label.font = UIFont.systemFont(ofSize: 50.0)
        label.text = "Hi!"
        label.sizeToFit()
        myView.addSubview(label)
        label.addGestureRecognizer(UIPanGestureRecognizer(target: myView, action: #selector(MyView.handlePan)))
        label.isUserInteractionEnabled = true
    




class MyView: UIView 

    func clampFrame(_ frame: CGRect, inBounds bounds: CGRect) -> CGRect 
        let center: CGPoint = CGPoint(x: max(bounds.minX + frame.width*0.5, min(frame.midX, bounds.maxX - frame.width*0.5)),
                                      y: max(bounds.minY + frame.height*0.5, min(frame.midY, bounds.maxY - frame.height*0.5)))
        return CGRect(x: center.x-frame.width*0.5, y: center.y-frame.height*0.5, width: frame.width, height: frame.height)
    

    func moveFrame(_ frame: CGRect, by translation: CGPoint, constrainedTo bounds: CGRect) -> CGRect 
        var newFrame = frame
        newFrame.origin.x += translation.x
        newFrame.origin.y += translation.y
        return clampFrame(newFrame, inBounds: bounds)
    

    private var startLocation: CGPoint = .zero
    private var startFrame: CGRect = .zero

    @objc func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) 
        guard let label = gestureRecognizer.view else  return 

        if gestureRecognizer.state == .began 
            startLocation = gestureRecognizer.location(in: self)
            startFrame = label.frame
         else if gestureRecognizer.state == .changed 
            let newLocation = gestureRecognizer.location(in: self)
            let translation = CGPoint(x: newLocation.x-startLocation.x, y: newLocation.y-startLocation.y)

            label.frame = moveFrame(startFrame, by: translation, constrainedTo: self.bounds)
        

    


【讨论】:

哇!! Matic,它很棒的解决方案..它也改善了我的平移。非常感谢!

以上是关于如何使用 UIPanGestureRecognizer 设置拖动控件的边界?的主要内容,如果未能解决你的问题,请参考以下文章

[精选] Mysql分表与分库如何拆分,如何设计,如何使用

如果加入条件,我该如何解决。如果使用字符串连接,我如何使用

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?

如何使用laravel保存所有行数据每个行名或相等