How to programmatically disable constraint when animating

时间:2019-01-18 18:54:01

标签: swift autolayout nslayoutconstraint

I am have a view with a fixed width anchored to the left. I want this view to animate (moving left to right) by anchoring it to the right (thus removing the left anchor). How do I do this?

I tried setting a priority but I am not sure of the syntax. I also tried to disable the constraint, but that did not work.

fileprivate func sparkle() {
    let sparkleView = UIView()
    sparkleView.backgroundColor = UIColor.yellow
    sparkleView.alpha = 0.5
    addSubview(sparkleView)
    sparkleView.translatesAutoresizingMaskIntoConstraints = false
    sparkleView.topAnchor.constraint(equalTo: topAnchor).isActive = true
    sparkleView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    sparkleView.widthAnchor.constraint(equalToConstant: frame.width / 5).isActive = true
    sparkleView.leftAnchor.constraint(equalTo: leftAnchor).priority = UILayoutPriorityDefaultLow // Doesn't work
    sparkleView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
    layoutIfNeeded()
    sparkleView.leftAnchor.constraint(equalTo: leftAnchor).isActive = false // Doesn't work
    sparkleView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
    UIView.animate(withDuration: 2, animations: {
        self.layoutIfNeeded()
    }) { (_) in
        sparkleView.removeFromSuperview()
    }
}

Currently, the width constraint gets broken since we are assigning a left and right anchor.

enter image description here

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x6000020b8eb0 UIView:0x7fc846d551d0.width == 15.35   (active)>

-- EDIT --

I have tried creating an instance variable to hold the constraint.

let leftCons = sparkleView.leftAnchor.constraint(equalTo: leftAnchor)
leftCons.isActive = true

I then tried to modify the priority

leftCons.priority = UILayoutPriorityDefaultLow

However, this causes error

'Mutating a priority from required to not on an installed constraint (or vice-versa) is not supported.  You passed priority 250 and the existing priority was 1000.'

Instead, I need to just set it as inactive (from the answers)

leftCons.active = false

-- Correct code if interested.. --

fileprivate func sparkle() {
    let sparkleView = UIView()
    sparkleView.backgroundColor = UIColor.yellow
    sparkleView.alpha = 0.5
    addSubview(sparkleView)
    sparkleView.translatesAutoresizingMaskIntoConstraints = false
    sparkleView.topAnchor.constraint(equalTo: topAnchor).isActive = true
    sparkleView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    sparkleView.widthAnchor.constraint(equalToConstant: frame.width / 5).isActive = true
    let leftCons = sparkleView.leftAnchor.constraint(equalTo: leftAnchor)
    leftCons.isActive = true
    layoutIfNeeded()
    leftCons.isActive = false
    sparkleView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
    UIView.animate(withDuration: 0.5, animations: {
        self.layoutIfNeeded()
    }) { (_) in
        sparkleView.removeFromSuperview()
    }
}

1 个答案:

答案 0 :(得分:1)

You need to create a var

var leftCon:NSLayoutConstraint!

then alter it , you problem is every line create a new constraint

sparkleView.widthAnchor.constraint(equalToConstant: frame.width / 5).isActive = true
sparkleView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
sparkleView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true

note: above 3 constraints create a conflict as the view can't be pinned to left and right at the same time with a width constraint that why you see the conflict break => NSLayoutConstraint:0x6000020b8eb0 UIView:0x7fc846d551d0.width == 15.35 (active)

regardless of the active assignment so those

sparkleView.leftAnchor.constraint(equalTo: leftAnchor).priority = UILayoutPriorityDefaultLow // Doesn't work 
sparkleView.leftAnchor.constraint(equalTo: leftAnchor).isActive = false // Doesn't work

are on the fly and don't alter the created constraint , so to be

leftCon = sparkleView.leftAnchor.constraint(equalTo: leftAnchor)
leftCon.isActive = true

Regarding this crash

'Mutating a priority from required to not on an installed constraint (or vice-versa) is not supported

you need to set the priority before the activation

leftCon.priority = UILayoutPriorityDefaultLow
leftCon.isActive = true