Как изменить ограничения автоматического макета после того, как они установлены при использовании constraintEqualToAnchor()?

Я пытаюсь настроить представление с помощью ограничений AutoLayout, используя constraintEqualToAnchor():

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()?, какой правильный способ изменить ограничение позже после того, как я их установил?

Ответ 1

Вам нужно деактивировать предыдущее ограничение при активации нового, чтобы вы не ограничивали свой просмотр. Для этого сохраните ссылку на каждое из ограничений как свойство в 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
    }
}

Ответ 2

Вот пример объявления ограничения c, на который будет ссылаться позже. Мы устанавливаем новое постоянное значение, а затем вызываем 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.layout()

Ответ 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 exactly like 
        // the old except that it has a different constant.

        c.constant = 123;

        // if needed
        // [self.view setNeedsUpdateConstraints];

        break;
    }
}

Ответ 4

Вот пример с оператором IF, который модифицирует StackView и View, когда нажата сегментация:

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
    }