【问题标题】:Swift Update ConstraintSwift 更新约束
【发布时间】:2015-01-09 21:26:53
【问题描述】:

我在UIView 中创建的按钮中添加了约束

func CreateButtonWithIndex(index:Int) {

    newButton.setTranslatesAutoresizingMaskIntoConstraints(false)

    self.view.addSubview(newButton)

    let newButtonConstraintL = NSLayoutConstraint(item: newButton, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50)
    let newButtonConstraintH = NSLayoutConstraint(item: newButton, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50)
    var newButtonConstraintX = NSLayoutConstraint(item: newButton, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: CGFloat(riga))
    var newButtonConstraintY = NSLayoutConstraint(item: newButton, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: CGFloat(colonna))

    view.addConstraints([newButtonConstraintX,newButtonConstraintY,newButtonConstraintH,newButtonConstraintL])

    var pan = UIPanGestureRecognizer(target:self, action:"pan:")
    pan.maximumNumberOfTouches = 2
    pan.minimumNumberOfTouches = 1
    newButton.addGestureRecognizer(pan)
}

func pan(rec:UIPanGestureRecognizer) {
  case .Ended: 
        if let subview = selectedView {
            if let button = rec.view as? UIButton {
                if let title = button.titleForState(.Normal){
                    button.setTranslatesAutoresizingMaskIntoConstraints(false)
                    let line = Float(p.x % snapX)
                    let column = Float(p.x % snapY)
                    let constraintL = NSLayoutConstraint(item: button, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50)
                    let constraintH = NSLayoutConstraint(item: button, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50)
                    var constraint2 = NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: CGFloat(line))
                    var constraint3 = NSLayoutConstraint(item: button, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: CGFloat(column))

                    view.addConstraints([constraint2,constraint3,constraintL.constraintH])
                }
            }
        }
}

在我的项目中,我的用户可以移动这些按钮,然后我尝试为识别的按钮添加更多约束,但我得到了一个无穷无尽的错误约束

  "<NSLayoutConstraint:0x7f8e5a4e9450 UIButton:0x7f8e5a644f60'Button6'.centerX == UIView:0x7f8e5a648bc0.centerX - 120>",
  "<NSLayoutConstraint:0x7f8e5a5be040 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7f8e5a648bc0(736)]>",
  "<NSAutoresizingMaskLayoutConstraint:0x7f8e5a5be1f0 h=-&- v=-&- 'UIView-Encapsulated-Layout-Left' H:|-(0)-[UIView:0x7f8e5a648bc0]   (Names: '|':UITransitionView:0x7f8e5a5a8190 )>",
  "<NSAutoresizingMaskLayoutConstraint:0x7f8e5a5b53b0 h=--& v=--& UIButton:0x7f8e5a644f60'Button6'.midX == + 200>"

将尝试通过打破约束来恢复

"<NSLayoutConstraint:0x7f8e5a4e9450 UIButton:0x7f8e5a644f60'Button6'.centerX == UIView:0x7f8e5a648bc0.centerX - 120>"

"<NSLayoutConstraint:0x7f8e5a4e9510 UIButton:0x7f8e5a644f60'Button6'.centerY == UIView:0x7f8e5a648bc0.centerY - 40>",
"<NSLayoutConstraint:0x7f8e5a5be1a0 'UIView-Encapsulated-Layout-Height' V:[UIView:0x7f8e5a648bc0(414)]>",
"<NSAutoresizingMaskLayoutConstraint:0x7f8e5a5be240 h=-&- v=-&- 'UIView-Encapsulated-Layout-Top' V:|-(0)-[UIView:0x7f8e5a648bc0]   (Names: '|':UITransitionView:0x7f8e5a5a8190 )>",
"<NSAutoresizingMaskLayoutConstraint:0x7f8e5a5b82d0 h=--& v=--& UIButton:0x7f8e5a644f60'Button6'.midY == + 189>"

将尝试通过打破约束来恢复

<NSLayoutConstraint:0x7f8e5a4e9510 UIButton:0x7f8e5a644f60'Button6'.centerY == UIView:0x7f8e5a648bc0.centerY - 40>

...我应该更新 newButtonConstraintX / Y 但我不明白我该怎么做吗?

【问题讨论】:

    标签: swift ios8 autolayout


    【解决方案1】:

    问题是您正在添加一个与现有约束冲突的新约束。

    你有几个选择:

    1. 在 iOS 8 中生效,您可以在添加新约束之前将约束的 active 属性设置为 false。

    2. 在 iOS 8 之前的版本中,您可能希望在添加新约束之前删除旧约束。

    3. 理想情况下,最好不必激活/停用(或者,更糟糕的是,添加和删除)约束,而只需修改单个约束的 constant 属性。例如在 Swift 3/4 中:

      class ViewController: UIViewController {
      
          private var xConstraint: NSLayoutConstraint!
          private var yConstraint: NSLayoutConstraint!
      
          override func viewDidLoad() {
              super.viewDidLoad()
      
              let label = UILabel()
              label.text = "x"
              label.translatesAutoresizingMaskIntoConstraints = false
              view.addSubview(label)
      
              // I don't really need to save references to these, so these are local variables
      
              let widthConstraint = label.widthAnchor.constraint(equalToConstant: 50)
              let heightConstraint = label.heightAnchor.constraint(equalToConstant: 50)
      
              // but since I'll be modifying these later, these are class properties
      
              xConstraint = label.centerXAnchor.constraint(equalTo: view.centerXAnchor)
              yConstraint = label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
      
              NSLayoutConstraint.activate([widthConstraint, heightConstraint, xConstraint, yConstraint])
      
              let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
              view.addGestureRecognizer(pan)
          }
      
          private var originalCenter: CGPoint!
      
          @objc func handlePan(_ gesture: UIPanGestureRecognizer) {
              if gesture.state == .began {
                  originalCenter = CGPoint(x: xConstraint.constant, y: yConstraint.constant)
              }
      
              let translation = gesture.translation(in: gesture.view!)
      
              xConstraint.constant = originalCenter.x + translation.x
              yConstraint.constant = originalCenter.y + translation.y
          }
      
      }
      

      当通过修改约束的constant可以达到想要的效果时,一般是最好的。

    有关 Swift 2 语法,请参阅previous revision of this answer。

    【讨论】:

    • 嗨@Rob,我正在使用相同的方法。我以编程方式添加了约束,现在更新常量,但它没有更新视图。
    • 我尝试了连接故事板中的约束并从 IBOutlet 更改其常量工作正常。
    【解决方案2】:

    看起来你只是在添加越来越多的约束。你不能这样做,因为它们显然相互冲突。您基本上是在说“将视图放在位置 x = 1、x = 2、x = 3、x = 4 和 x = 5”。

    您必须删除旧的约束。您有两种选择。

    1. 将约束保存在数组中,并在添加新约束之前从视图中删除这些约束。

    2. 或者您保留对更改和调整其属性的约束的引用。

    由于您的约束只是常量值不同,您应该选择选项 2。

    将newButtonConstraintX 和newButtonConstraintY 设为viewController 的变量。

    例如

    class ViewController: UIViewController {
        var newButtonConstraintX: NSLayoutConstraint!
        var newButtonConstraintY: NSLayoutConstraint!
    
    
        func CreateButtonWithIndex(index:Int) {
    
            newButtonConstraintX = NSLayoutConstraint(item: newButton, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: CGFloat(riga))
    
            newButtonConstraintY = NSLayoutConstraint(item: newButton, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: CGFloat(colonna))
    
            /* ... */
        }
    
        func pan(rec:UIPanGestureRecognizer) {  
            /* ... */
            newButtonConstraintX.constant = line
            newButtonConstraintY.constant = column
            button.layoutIfNeeded()
        }
    

    【讨论】:

      【解决方案3】:

      更新 Rob 对 Swift 3 的回答:

      class ViewController: UIViewController {
      
          private var xConstraint: NSLayoutConstraint!
          private var yConstraint: NSLayoutConstraint!
      
          override func viewDidLoad() {
          super.viewDidLoad()
      
          let label = UILabel()
          label.text = "x"
          label.setTranslatesAutoresizingMaskIntoConstraints(false)
          view.addSubview(label)
      
          // I don't really need to save references to these, so these are local variables
      
      
          let widthConstraint = NSLayoutConstraint(item: drugToDrugView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 50)
          let heightConstraint = NSLayoutConstraint(item: drugToDrugView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 50)
      
          // but since I'll be modifying these later, these are class properties
      
          xConstraint = NSLayoutConstraint(item: drugToDrugView, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1.0, constant: 0)
          yConstraint = NSLayoutConstraint(item: drugToDrugView, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1.0, constant: 0)
      
          drugToDrugView.addConstraints([widthConstraint, heightConstraint, xConstraint, yConstraint])
      
          let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
          view.addGestureRecognizer(pan)
      
       }
      
       private var originalCenter: CGPoint!
      
       func handlePan(gesture: UIPanGestureRecognizer) {
          if gesture.state == .began {
              originalCenter = CGPoint(x: xConstraint.constant, y: yConstraint.constant)
          }
      
          let translation = gesture.translation(in: gesture.view!)
      
          xConstraint.constant = originalCenter.x + translation.x
          yConstraint.constant = originalCenter.y + translation.y
          view.setNeedsLayout()
      }
      

      【讨论】:

      • 不更新视图。
      猜你喜欢
      • 1970-01-01
      • 2018-06-17
      • 2021-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-16
      • 2015-05-06
      • 1970-01-01
      相关资源
      最近更新 更多