【问题标题】:How to change Auto Layout constraints after they are set when using constraintEqualToAnchor()?使用 constraintEqualToAnchor() 设置自动布局约束后如何更改它们?
【发布时间】:2016-03-27 07:04:01
【问题描述】:

我尝试使用 constraintEqualToAnchor() 设置具有 AutoLayout 约束的视图:

override func viewDidLoad() {
    super.viewDidLoad()

    let myView = UIView()
    myView.backgroundColor = UIColor.orangeColor()
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    myView.leftAnchor.constraintEqualToAnchor(view.leftAnchor).active = true
    myView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true
    myView.topAnchor.constraintEqualToAnchor(view.topAnchor).active = true
    myView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor).active = true

    /******************************************/
    /* I try to change one of the constraints */
    /******************************************/
    myView.leftAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -100).active = true  
}

在最后一行代码中,我尝试更改其中一个约束。我认为它会起作用,但它在控制台日志中给出了一些错误

"<NSLayoutConstraint:0x7fb53a5180d0 H:|-(0)-[UIView:0x7fb53a5190b0](LTR)   (Names: '|':UIView:0x7fb53a519240 )>",
"<NSLayoutConstraint:0x7fb53a51f660 H:[UIView:0x7fb53a519240]-(-100)-[UIView:0x7fb53a5190b0](LTR)>",
"<NSLayoutConstraint:0x7fb53a711ee0 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7fb53a519240(414)]>"

当使用constraintEqualToAnchor()? 时,在我设置它们之后更改约束的正确方法是什么?

【问题讨论】:

  • 我想我可以先将myView.leftAnchor.constraintEqualToAnchor(view.leftAnchor).active 设置为false,然后再更改它(最后一行),但它仍然失败。我想我在这里有一些误解......
  • 您是否尝试过保留对约束的引用,然后直接设置常量?您不能继续对视图应用新的约束,否则它将变得过度约束。
  • @LucasDerraugh 我不确定如何使用布局锚点。你能告诉我答案中的代码吗?
  • 让我给你打一个。
  • @LucasDerraugh 是的,我以为我正在覆盖现有的约束,但我也发现我实际上是在添加新的约束。但是,问题是我不知道如何首先使用“布局锚”方法删除/停用现有约束。

标签: ios swift uiview autolayout nslayoutconstraint


【解决方案1】:

以下是if 语句在分段单击时修改StackViewView 的示例:

if (sender as AnyObject).selectedSegmentIndex == 0{
    // Shrink the white view and stack view
    heightConstraintView = containerView.heightAnchor.constraint(equalToConstant: 100)
    heightConstraintView?.isActive = true
    heightConstraintStackView = stackView.heightAnchor.constraint(equalToConstant: 100)
    heightConstraintStackView?.isActive = true
} else {
    // Before returning back the white view and stack view DEACTIVATE teh previous constraints
    heightConstraintView?.isActive = false
    heightConstraintStackView?.isActive = false
    // Returning back the white view and stack view to normal size
    heightConstraintView = containerView.heightAnchor.constraint(equalToConstant: 200)
    heightConstraintView?.isActive = true
    heightConstraintStackView = stackView.heightAnchor.constraint(equalToConstant: 200)
    heightConstraintStackView?.isActive = true
}

【讨论】:

    【解决方案2】:

    这是一个声明约束c 的示例,稍后将引用该约束。我们设置一个新的常量值,然后在 superview 上调用layout

    myView.translatesAutoresizingMaskIntoConstraints = false
    
    var constraints: [NSLayoutConstraint] = [
        myView.topAnchor.constraintEqualToAnchor(view.topAnchor),
        myView.leftAnchor.constraintEqualToAnchor(view.leftAnchor),
        myView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor)
    ]         
    let c = myView.rightAnchor.constraintEqualToAnchor(view.rightAnchor)       
    constraints.append(c)   
    
    view.addSubview(myView)
    NSLayoutConstraint.activateConstraints(constraints)
    
    // Some time later
    c.constant = -100
    view.setNeedsLayout()
    

    【讨论】:

    • 分配一个新的常量不能解决我的问题。我需要删除一个约束并添加一个新约束。是否可以删除/停用约束?
    • 你可以看到我的最后一行不仅仅是改变常量值,而是一个新的约束。左锚与父左锚对齐,我想将其更改为与父右锚负 100 对齐。这不仅仅是一个恒定的变化。
    • 我在网上发现了这种不断变化的情况,但是我只是找不到如何删除/停用约束,以便我可以在运行时以编程方式添加新约束。
    • @Joe 如果您所做的只是更改常量,则不应创建新的约束。你没有理由不能用这种方法完成你在问题中所说的。
    • 考虑到要自动处理的方向,在我的情况下很难使用常量。当考虑到用户可能在任何给定时间改变方向时,如何使用常量将视图放置在屏幕外(frame.width + 1 精确)
    【解决方案3】:
    // method myView.topAnchor.constraintEqualToAnchor creates new one inactive anchor 
    // and not returns exist with equal relationships     
    
    // you can set identifier for any constraint in Interface Builder or code and find & update in code
    for ( NSLayoutConstraint *c in [self.view constraintsAffectingLayoutForAxis:UILayoutConstraintAxisHorizontal] )
    {
        if ( YES == [c.identifier isEqualToString:@"my.layout-constraint.id"] )
        {
            // Unlike the other properties, the constant can be modified
            // after constraint creation. 
            // Setting the constant on an existing constraint performs much better 
            // than removing the constraint and adding a new one that's exactly like 
            // the old except that it has a different constant.
    
            c.constant = 123;
    
            // if needed
            // [self.view setNeedsUpdateConstraints];
    
            break;
        }
    }
    

    【讨论】:

      【解决方案4】:

      您需要在激活新约束时停用先前的约束,以免最终过度约束您的视图。为此,请将每个约束的引用作为属性存储在 ViewController 中,然后在创建和激活新约束之前将旧约束的 active 属性设置为 false

      Swift 2.x:

      class ViewController: UIViewController {
          var leftConstraint: NSLayoutConstraint?
          var trailingConstraint: NSLayoutConstraint?
          var topConstraint: NSLayoutConstraint?
          var bottomConstraint: NSLayoutConstraint?
      
          override func viewDidLoad() {
              super.viewDidLoad()
      
              let myView = UIView()
              myView.backgroundColor = UIColor.orangeColor()
              myView.translatesAutoresizingMaskIntoConstraints = false
              view.addSubview(myView)
      
              leftConstraint = myView.leftAnchor.constraintEqualToAnchor(view.leftAnchor)
              leftConstraint?.active = true
      
              trailingConstraint = myView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor)
              trailingConstraint?.active = true
      
              topConstraint = myView.topAnchor.constraintEqualToAnchor(view.topAnchor)
              topConstraint?.active = true
      
              bottomConstraint = myView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor)
              bottomConstraint?.active = true
      
              /******************************************/
              /* I try to change one of the constraints */
              /******************************************/
              leftConstraint?.active = false
              leftConstraint = myView.leftAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -100)
              leftConstraint?.active = true
          }
      }
      

      Swift 3 语法更新:

      class ViewController: UIViewController {
          var leftConstraint: NSLayoutConstraint?
          var trailingConstraint: NSLayoutConstraint?
          var topConstraint: NSLayoutConstraint?
          var bottomConstraint: NSLayoutConstraint?
      
          override func viewDidLoad() {
              super.viewDidLoad()
      
              let myView = UIView()
              myView.backgroundColor = UIColor.orange
              myView.translatesAutoresizingMaskIntoConstraints = false
              view.addSubview(myView)
      
              leftConstraint = myView.leftAnchor.constraint(equalTo: view.leftAnchor)
              leftConstraint?.isActive = true
      
              trailingConstraint = myView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
              trailingConstraint?.isActive = true
      
              topConstraint = myView.topAnchor.constraint(equalTo: view.topAnchor)
              topConstraint?.isActive = true
      
              bottomConstraint = myView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
              bottomConstraint?.isActive = true
      
              /******************************************/
              /* I try to change one of the constraints */
              /******************************************/
              leftConstraint?.isActive = false
              leftConstraint = myView.leftAnchor.constraint(equalTo: view.rightAnchor, constant: -100)
              leftConstraint?.isActive = true
          }
      }
      

      【讨论】:

      • 太棒了,谢谢!我想知道为什么我需要一个变量来存储约束,为什么我不能直接更改.active=false(即 myView.leftAnchor.constraintEqualToAnchor(view.leftAnchor).active = false)?
      • myView.leftAnchor.constraintEqualToAnchor(view.leftAnchor) 创建一个新的约束。它不访问旧的。
      • 我明白了,谢谢!是否有可能对这种约束变化进行动画处理?我实际上是在尝试通过更改约束来实现页面滑入效果。我刚刚尝试了UIView.animation(),除非我使用“常量”,否则没有动画(但我希望我不需要使用常量)。
      • 我相信您应该能够为该更改设置动画。在循环内调用layoutIfNeeded()UIView.animateWithDuration(1.0) { self.view.layoutIfNeeded() }
      • 是的,你是对的。动画,谢谢!但有趣的是,它没有。如果我将顶部/宽度/高度约束设置为等于父级的顶部/宽度/高度,并且左锚与父级的右锚对齐并尝试将左锚设置为父级的左锚。在这种情况下(滑动效果),它没有动画。如果我将左锚点设置为父级的左锚点,然后尝试对父级的右锚点进行动画处理,在这种情况下(滑出),它会进行动画处理。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-14
      • 2014-03-24
      相关资源
      最近更新 更多