Ios 如何使用平移手势识别器更改不同视图的布局约束?

Ios 如何使用平移手势识别器更改不同视图的布局约束?,ios,swift,uigesturerecognizer,Ios,Swift,Uigesturerecognizer,我有一个功能,每次按下按钮时,都会向主视图添加一个新的UIView。我希望每个视图都可以拖动。目前,我正在为每个视图添加一个平移手势识别器,从而更改每个视图的布局约束 我的问题是,我没有在移动每个视图之前正确禁用其原始约束,因此新约束和旧约束相互冲突 这是我的密码: import UIKit class ViewController5: UIViewController, UINavigationControllerDelegate, UIGestureRecognizerDelegate {

我有一个功能,每次按下按钮时,都会向主视图添加一个新的
UIView
。我希望每个视图都可以拖动。目前,我正在为每个视图添加一个平移手势识别器,从而更改每个视图的布局约束

我的问题是,我没有在移动每个视图之前正确禁用其原始约束,因此新约束和旧约束相互冲突

这是我的密码:

import UIKit

class ViewController5: UIViewController, UINavigationControllerDelegate, UIGestureRecognizerDelegate {

var textPosXConstraint = NSLayoutConstraint()
var textPosYConstraint = NSLayoutConstraint()

var numberOfViews = 0

var startingConstantPosX: CGFloat  = 0.0
var startingConstantPosY: CGFloat  = 100.0

override func viewDidLoad() {
    super.viewDidLoad()

    navigationItem.title = "edit views"
    navigationItem.rightBarButtonItem = UIBarButtonItem(title: "add", style: .plain, target: self, action: #selector(addView))
    navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Clear", style: .plain, target: self, action: #selector(clearThis))
}

@objc func addView() {

    let view1 = UIView()
    view1.backgroundColor = UIColor.yellow
    view1.frame = CGRect()
    view.addSubview(view1)
    view1.translatesAutoresizingMaskIntoConstraints = false

    view1.widthAnchor.constraint(equalToConstant: 80).isActive = true
    view1.heightAnchor.constraint(equalToConstant: 80).isActive = true

    textPosXConstraint = view1.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0)
    textPosXConstraint.isActive = true

    textPosYConstraint = view1.centerYAnchor.constraint(equalTo: view.topAnchor, constant: 100)
    textPosYConstraint.isActive = true

    numberOfViews+=1
    view1.tag = numberOfViews

    //add pan gesture
    let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
    panGestureRecognizer.delegate = self
    view1.addGestureRecognizer(panGestureRecognizer)
}

@objc func clearThis() {
    for view in view.subviews {
        view.removeFromSuperview()
    }
    numberOfViews = 0
}

@objc func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {

    guard let currentView = gestureRecognizer.view else { return }

    if gestureRecognizer.state == .began {

        print("view being moved is: \(currentView.tag)")

        startingConstantPosY = textPosYConstraint.constant
        startingConstantPosX = textPosXConstraint.constant

    } else if gestureRecognizer.state == .changed {

        let translation = gestureRecognizer.translation(in: self.view)

        let newXConstant = self.startingConstantPosX + translation.x
        let newYConstant = self.startingConstantPosY + translation.y

        currentView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: startingConstantPosX).isActive = false
        currentView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: newXConstant).isActive = true

    }
}
}
理想情况下,它将工作,以便用户可以添加任意多的视图,并移动每个视图


谢谢你的帮助

您需要保留对为视图创建的位置约束的引用,以便您可以在创建新约束之前更改其
常量
值或设置
isActive=false

moveableView.horizontalConstraint?.isActive = false
moveableView.verticalConstraint?.isActive = false

moveableView.horizontalConstraint = ...
moveableView.horizontalConstraint?.isActive = true

moveableView.verticalConstraint = ...
moveableView.verticalConstraint?.isActive = true
  • 创建名为
    MovableView
    UIView
    子类,该子类具有
    NSLayoutConstraint?
    横向约束和
    垂直约束
    的属性
  • 在设置约束的
    isActive=true
    之前,在创建约束时设置这些属性
  • 当需要移动
    MovableView
    时,更新
    水平约束
    垂直约束
    常量
    属性

    moveableView.horizontalConstraint?.constant = newXConstant
    moveableView.verticalConstraint?.constant = newYConstant
    
    或者,您可以在创建、分配和激活新约束之前设置
    水平约束?.isActive=false
    垂直约束?.isActive=false

    moveableView.horizontalConstraint?.isActive = false
    moveableView.verticalConstraint?.isActive = false
    
    moveableView.horizontalConstraint = ...
    moveableView.horizontalConstraint?.isActive = true
    
    moveableView.verticalConstraint = ...
    moveableView.verticalConstraint?.isActive = true
    
  • 有关我4年前编写的可拖动视图的实现,请参见。它已经过时,需要更新,但你可能会从中得到一些想法。还请阅读下面的注释,其中@Matt解释说,对于可拖动视图,可以跳过使用约束。可以向屏幕添加不参与自动布局的视图,即使屏幕的其余部分参与自动布局


    我修正了你的代码:

    • 您没有提供
      MovableView
      的实现,但约束属性似乎是
      static
      而不是成员属性。为了支持多个可移动视图,需要将它们作为成员属性
    • 您交换了
      startingConstantPosX
      startingConstantPosY
      ,这就是导致跳转的原因


    如果每次调用
    handlePan
    时都将
    translation
    设置回
    .zero
    ,则无需跟踪起始位置即可简化代码:

    @objc func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
    
        guard let currentView = gestureRecognizer.view as? MovableView else { return }
    
        if gestureRecognizer.state == .began {
    
            print("view being moved is: \(currentView.tag)")
    
        } else if gestureRecognizer.state == .changed {
    
            let translation = gestureRecognizer.translation(in: self.view)
    
            currentView.horizontalConstraint?.constant += translation.x
            currentView.verticalConstraint?.constant += translation.y
    
            gestureRecognizer.setTranslation(.zero, in: self.view)
        }
    }
    

    谢谢你的回答-我实现了它,它朝着正确的方向发展,但是当我第二次尝试拖动一个视图时,它会飞出屏幕。如果你有任何想法,这就是我得到的--我也同意,跳过自动布局会更容易,我一开始是这样做的,但这些最终将是UITextView,当你输入它们时会扩展,所以我需要约束条件。再次感谢:)哇,这太棒了-非常感谢你的帮助!我真的很感激!:)