拖动时调整 UIView 框架

Adjust UIView frame on dragging

我正在尝试在拖动时更改 UIView 框架。我将 UIView 子类化并编写了 touchesBegantouchesMoved 方法。他们在这里:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let touch = touches.first
    startPosition = touch?.locationInView(self)
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let touch = touches.first
    let endPosition = touch?.locationInView(self)
    let difference = endPosition!.y - startPosition.y
    let newFrame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.width, self.frame.height + difference)
    self.frame = newFrame
}

但结果我遇到了意想不到的行为。描述起来有点困难。 Here's video how it works.。小阻力(约 20px)使框架变大约 100px。

我的自定义视图也有一些限制。自定义视图底部的图像应始终保留在那里:

所以问题是:

  1. 如何根据用户拖动的距离使视图变大。
  2. 以及为什么更改框架后约束不适用以及如何再次应用它们?

您的视图快速增长的原因是您始终使用自第一次触地以来移动的距离来更新当前视图高度。不要修改当前高度,您应该始终将移动的距离添加到视图的原始高度。

向您的自定义视图添加另一个 属性 以跟踪视图的原始高度。在 touchesBegan 中设置它,然后在计算 touchesMoved 中的帧时使用 originalHeight:

class CustomView: UIView {

    var startPosition: CGPoint?
    var originalHeight: CGFloat = 0

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let touch = touches.first
        startPosition = touch?.locationInView(self)
        originalHeight = self.frame.height
    }

    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let touch = touches.first
        let endPosition = touch?.locationInView(self)
        let difference = endPosition!.y - startPosition!.y
        let newFrame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.width, originalHeight + difference)
        self.frame = newFrame
    }

}

And why constraints do not apply after changing frame and how to apply them again?

你真的不应该在使用自动布局时更新框架。执行此操作的正确方法是向视图的高度约束添加 @IBOutlet,然后在您希望更改视图的高度时更新约束的 constant 属性。

执行此操作时,自动布局将使用更新后的高度正确定位自定义视图的子视图。

要将 @IBOutlet 添加到您的代码的高度限制,Control - 从 文档大纲 [=41] 中的高度限制拖动=] 到您的 viewController。给它起一个名字,例如 customViewHeight.

由于更新视图高度的代码在视图代码本身中,因此 viewController 将高度约束分配给 viewDidLoad 中的自定义视图。然后自定义视图可以更新高度约束的 constant 属性 来调整视图的大小。

class ViewController: UIViewController {

    @IBOutlet weak var customViewHeight: NSLayoutConstraint!

    @IBOutlet weak var customView: CustomView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Assign the layout constraint to the custom view so that it can update it itself
        customView.customViewHeight = customViewHeight
    }
}

class CustomView: UIView {

    var startPosition: CGPoint?
    var originalHeight: CGFloat = 0
    var customViewHeight: NSLayoutConstraint!

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let touch = touches.first
        startPosition = touch?.locationInView(self)
        originalHeight = customViewHeight.constant
    }

    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let touch = touches.first
        let endPosition = touch?.locationInView(self)
        let difference = endPosition!.y - startPosition!.y
        customViewHeight.constant = originalHeight + difference
    }

}

对于您的情况,我认为您应该更改底部约束的常量而不是更改视图的框架。顺便说一句,你最好使用手势而不是重写触摸方法,因为手势级别更高 API 并且更易于维护

基本上,使用自动布局的项目应避免使用框架更改视图。