Remove all constraints affecting a UIView

xcode remove constraints programmatically
swift 4 remove constraint
remove constraint at runtime swift
how to remove bottom constraint in swift
nslayoutconstraint
uiview removeconstraints
constraints in swift
break constraint swift

I have a UIView which is placed on the screen via several constraints. Some of the constraints are owned by the superview, others are owned by other ancestors (e.g. perhaps the view property of a UIViewController).

I want to remove all of these old constraints, and place it somewhere new using new constraints.

How can I do this without creating an IBOutlet for every single constraint and having to remember which view owns said constraint?

To elaborate, the naive approach would be to create a bunch of IBOutlets for each of the constraints, and would then involve calling code such as:

[viewA removeConstraint:self.myViewsLeftConstraint];
[viewB removeConstraint:self.myViewsTopConstraint];
[viewB removeConstraint:self.myViewsBottomConstraint];
[self.view removeConstraint:self.myViewsRightConstraint];

The problem with this code is that even in the simplest case, I would need to create 2 IBOutlets. For complex layouts, this could easily reach 4 or 8 required IBOutlets. Furthermore, I would need to ensure that my call to remove the constraint is being called on the proper view. For example, imagine that myViewsLeftConstraint is owned by viewA. If I were to accidentally call [self.view removeConstraint:self.myViewsLeftConstraint], nothing would happen.

Note: The method constraintsAffectingLayoutForAxis looks promising, but is intended for debugging purposes only.


Update: Many of the answers I am receiving deal with self.constraints, self.superview.constraints, or some variant of those. These solutions won't work since those methods return only the constraints owned by the view, not the ones affecting the view.

To clarify the problem with these solutions, consider this view hierarchy:

  • Grandfather
    • Father
      • Me
        • Son
        • Daughter
      • Brother
    • Uncle

Now imagine we create the following constraints, and always attach them to their nearest common ancestor:

  • C0: Me: same top as Son (owned by Me)
  • C1: Me: width = 100 (owned by Me)
  • C2: Me: same height as Brother (owned by Father)
  • C3: Me: same top as Uncle (owned by Grandfather)
  • C4: Me: same left as Grandfather (owned by Grandfather)
  • C5: Brother: same left as Father (owned by Father)
  • C6: Uncle: same left as Grandfather (owned by Grandfather)
  • C7: Son: same left as Daughter (owned by Me)

Now imagine we want to remove all constraints affecting Me. Any proper solution should remove [C0,C1,C2,C3,C4] and nothing else.

If I use self.constraints (where self is Me), I will get [C0,C1,C7], since those are the only constraints owned by Me. Obviously it wouldn't be enough to remove this since it is missing [C2,C3,C4]. Furthermore, it is removing C7 unnecessarily.

If I use self.superview.constraints (where self is Me), I will get [C2,C5], since those are the constraints owned by Father. Obviously we cannot remove all these since C5 is completely unrelated to Me.

If I use grandfather.constraints, I will get [C3,C4,C6]. Again, we cannot remove all of these since C6 should remain intact.

The brute force approach is to loop over each of the view's ancestors (including itself), and seeing if firstItem or secondItem are the view itself; if so, remove that constraint. This will lead to a correct solution, returning [C0,C1,C2,C3,C4], and only those constraints.

However, I'm hoping there is a more elegant solution than having to loop through the entire list of ancestors.

This approach worked for me:

@interface UIView (RemoveConstraints)

- (void)removeAllConstraints;

@end


@implementation UIView (RemoveConstraints)

- (void)removeAllConstraints
{
    UIView *superview = self.superview;
    while (superview != nil) {
        for (NSLayoutConstraint *c in superview.constraints) {
            if (c.firstItem == self || c.secondItem == self) {
                [superview removeConstraint:c];
            }
        }
        superview = superview.superview;
    }

    [self removeConstraints:self.constraints];
    self.translatesAutoresizingMaskIntoConstraints = YES;
}

@end

After it's done executing your view remains where it was because it creates autoresizing constraints. When I don't do this the view usually disappears. Additionally, it doesn't just remove constraints from superview but traversing all the way up as there may be constraints affecting it in ancestor views.

Swift 4 Version
extension UIView {

    public func removeAllConstraints() {
        var _superview = self.superview

        while let superview = _superview {
            for constraint in superview.constraints {

                if let first = constraint.firstItem as? UIView, first == self {
                    superview.removeConstraint(constraint)
                }

                if let second = constraint.secondItem as? UIView, second == self {
                    superview.removeConstraint(constraint)
                }
            }

            _superview = superview.superview
        }

        self.removeConstraints(self.constraints)
        self.translatesAutoresizingMaskIntoConstraints = true
    }
}

Is there a way to remove all constraints on a UIView? · Issue #57 , Removes all explicit constraints that affect the view. WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you  I have a UIView which is placed on the screen via several constraints. Some of the constraints are owned by the superview, others are owned by other ancestors (e.g. perhaps the view property of a

The only solution I have found so far is to remove the view from its superview:

[view removeFromSuperview]

This looks like it removes all constraints affecting its layout and is ready to be added to a superview and have new constraints attached. However, it will incorrectly remove any subviews from the hierarchy as well, and get rid of [C7] incorrectly.

Remove all constraints affecting a UIView, I have a UIView which is placed on the screen via several constraints. Some of the constraints are owned by the superview, others are owned  Adds a constraint on the layout of the receiving view or its subviews. func add Constraints ([NSLayout Constraint]) Adds multiple constraints on the layout of the receiving view or its subviews.

You can remove all constraints in a view by doing this:

[_cell.contentView removeConstraints:_cell.contentView.constraints];

EDIT: To remove the constraints of all subviews, use the following extension in Swift:

extension UIView {
    func clearConstraints() {
        for subview in self.subviews {
            subview.clearConstraints()
        }
        self.removeConstraints(self.constraints)
    }
}

removeConstraints(_:), Parameters. constraints. The constraints to remove. Adds multiple constraints on the layout of the receiving view or its subviews. So, if you want to remove all constraints for a view, the easiest way is to remove that view from the view hierarchy (which automatically removes all of its constraints), and then re-add it into the view hierarchy again with new constraints. That's assuming you have a single view with no subviews of its own.

In Swift:

import UIKit

extension UIView {

    /**
     Removes all constrains for this view
     */
    func removeConstraints() {

        let constraints = self.superview?.constraints.filter{
            $0.firstItem as? UIView == self || $0.secondItem as? UIView == self
        } ?? []

        self.superview?.removeConstraints(constraints)
        self.removeConstraints(self.constraints)
    }
}

removeConstraint(_:), constraint to remove. Removing a constraint not held by the view has no effect. Adds multiple constraints on the layout of the receiving view or its subviews. Adds multiple constraints on the layout of the receiving view or its subviews. func remove Constraint (NSLayout Constraint) Removes the specified constraint from the view.

There are two ways of on how to achieve that according to Apple Developer Documentation

1. NSLayoutConstraint.deactivateConstraints

This is a convenience method that provides an easy way to deactivate a set of constraints with one call. The effect of this method is the same as setting the isActive property of each constraint to false. Typically, using this method is more efficient than deactivating each constraint individually.

// Declaration
class func deactivate(_ constraints: [NSLayoutConstraint])

// Usage
NSLayoutConstraint.deactivate(yourView.constraints)
2. UIView.removeConstraints (Deprecated for >= iOS 8.0)

When developing for iOS 8.0 or later, use the NSLayoutConstraint class’s deactivateConstraints: method instead of calling the removeConstraints: method directly. The deactivateConstraints: method automatically removes the constraints from the correct views.

// Declaration
func removeConstraints(_ constraints: [NSLayoutConstraint])`

// Usage
yourView.removeConstraints(yourView.constraints)
Tips

Using Storyboards or XIBs can be such a pain at configuring the constraints as mentioned on your scenario, you have to create IBOutlets for each ones you want to remove. Even so, most of the time Interface Builder creates more trouble than it solves.

Therefore when having very dynamic content and different states of the view, I would suggest:

  1. Creating your views programmatically
  2. Layout them and using NSLayoutAnchor
  3. Append each constraint that might get removed later to an array
  4. Clear them every time before applying the new state

Simple Code

private var customConstraints = [NSLayoutConstraint]()

private func activate(constraints: [NSLayoutConstraint]) {
    customConstraints.append(contentsOf: constraints)
    customConstraints.forEach { $0.isActive = true }
}

private func clearConstraints() {
    customConstraints.forEach { $0.isActive = false }
    customConstraints.removeAll()
}

private func updateViewState() {
    clearConstraints()

    let constraints = [
        view.leadingAnchor.constraint(equalTo: parentView.leadingAnchor),
        view.trailingAnchor.constraint(equalTo: parentView.trailingAnchor),
        view.topAnchor.constraint(equalTo: parentView.topAnchor),
        view.bottomAnchor.constraint(equalTo: parentView.bottomAnchor)
    ]

    activate(constraints: constraints)

    view.layoutIfNeeded()
}
References
  1. NSLayoutConstraint
  2. UIView

Objective C: removing UIStoryboard constraints programmatically, Objective C: removing UIStoryboard constraints programmatically UIView *​superview = view.superview; [view removeFromSuperview]; [superview Pingback: Remove all constraints affecting a UIView - DexPage  If the view’s superview is not nil, the superview releases the view. Calling this method removes any constraints that refer to the view you are removing, or that refer to any view in the subtree of the view you are removing. func add Subview (UIView) func bring Subview To Front (UIView)

Auto Layout in Swift: Writing constraints programmatically, Auto Layout Constraints written programmatically in code by making use You might think that we can be happy with the idea that SwiftUI will solve this after all. be translated into Auto Layout constraints and affecting your constraints. Each UIView comes with a collection of anchor properties that allow  The returned set of constraints may not all include the view explicitly. Constraints that impact the location of the view implicitly may also be included. While this provides a good starting point for debugging, there is no guarantee that the returned set of constraints will include all of the constraints that have an impact on the view’s layout in the given orientation.

Working with Xcode Auto Layout in Swift and iOS Projects, You can also alter the device's orientation to see how it affects our app's UI. To properly set up the constraints in our project, first clear all the  Do not deactivate all your constraints, then reactivate the ones you need. Instead, your app must have some way of tracking your constraints, and validating them during each update pass. Only change items that need to be changed. During each update pass, you must ensure that you have the appropriate constraints for the app’s current state.

1. Views - Programming iOS 9 [Book], Views A view (an object whose class is UIView or a subclass of UIView) knows Oddly, there is no command for removing all of a view's subviews at once. Autolayout: Autolayout, introduced in iOS 6, depends on the constraints of views. I spent a lot of wasted time building up constraints with the new NSAnchorLayout class and subclasses. These work just fine but it took me a while to realize that all the constraints that I needed already existed in the storyboard. If you build constraints in code then most certainly use this method to aggregate your constraints:

Comments
  • How about you put an identifier to all the constraints you want to remove ? This way you do not need to keep an outlet for them.
  • This should be the official answer.
  • why do you have self.translatesAutoresizingMaskIntoConstraints = YES; ? you literally never want this for views you are setting up with constraints?
  • I'm removing the constraints, so I want to use the autoresize constraints after I remove the other constraints to hold it in place, without that line in my code the view would disappear
  • I needed to log all constraints on a view for debugging purposes and I was able to modify this answer slightly to do that. +1
  • This would incorrectly remove C7. However, it should be easy to fix if you remove [self removeConstraints:self.constraints]; and change UIView *superview = self.superview; to UIView *superview = self;.
  • You could use the firstItem and secondItem properties of the constraints to check if they apply to your view and loop through the view hierarchy to find all of them. I think removing and re-adding is a better solution, though. I'd be interested to see your use case since it seems like this is a very bad thing to be doing. Your constraints could easily become completely invalid since other views may be relying on those constraints to lay out properly.
  • @bjtitus: Good point. However, in this specific case, I am repositioning a view which has nothing dependent on it. It uses other views in order to know where to be placed, and there are no views that use it in order to know where to be placed.
  • Not the only solution, but very simple. In my use case I have just removed the view from superview and then re-added it later.
  • The problem with this solution is that it removes only the constraints that this view owns (e.g. its width and height). It does not remove things such as the leading and top constraints.
  • I haven't verified your comment above. However, I believe this would work the same as or better than above, [NSLayoutConstraint deactivateConstraints:self.constraints];
  • That would suffer from the same problem as the original solution. self.constraints only returns the constraints that self owns, not all the constraints that affect self.