Remove any restrictions affecting the UIView.

I have a UIView that fits on the screen with a few limitations. Some of the restrictions belong to the superwin, others belong to other ancestors (for example, perhaps, the view property of the UIViewController).

I want to remove all of these old restrictions and put it somewhere new, using the new restrictions.

How can I do this without creating an IBOutlet for each individual constraint and don’t remember which representation belongs to the specified constraint?

To develop, a naive approach would be to create an IBOutlets group for each of the constraints and then include a call code, for example:

[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 can easily achieve the 4 or 8 required IBOutlets. In addition, I will need to make sure that my call to remove the constraint is called in the correct view. For example, imagine myViewsLeftConstraint belongs to viewA . If I accidentally called [self.view removeConstraint:self.myViewsLeftConstraint] , nothing would happen.

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




Update:. Many of the answers I get deal with self.constraints , self.superview.constraints or some variations. These solutions will not work, because these methods return only restrictions that belong to the view, and not those that affect the view.

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

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

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

  • C0: Me: the same top as the Son (belongs to me)
  • C1: Me: width = 100 (belongs to me)
  • C2: Me: same height as brother (belongs to father)
  • C3: Me: same top as uncle (belonging to grandfather).
  • C4: Me: the same as grandfather (belonging to grandfather).
  • C5: Brother: the same as the Father (belongs to the father)
  • C6: Uncle: the same as grandfather (belonging to grandfather).
  • C7: Son: the same as the Daughter (belongs to me).

Now imagine that we want to remove all restrictions affecting Me . Any correct 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] , as these are the only restrictions Me has. Obviously, this would not be enough to remove it, since it is missing [C2,C3,C4] . In addition, it unnecessarily removes C7 .

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

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

The brute force approach is to loop over each of the ancestors of the ancestors (including yourself) and see if firstItem or secondItem the view itself; if so, remove this restriction. This will lead to the correct solution, returning [C0,C1,C2,C3,C4] and only these restrictions.

However, I hope there is a more elegant solution than having to go through the entire list of ancestors.

+70
ios objective-c autolayout uiview constraints
Jun 25 '14 at 21:27
source share
13 answers

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

 [view removeFromSuperview] 

It seems that he removes all the restrictions that affect his layout, and he is ready to be added to the supervisor and is tied to new restrictions. However, it will incorrectly remove any children from the hierarchy, and it will also incorrectly get rid of [C7] .

+41
Jun 25 '14 at 21:46
source share

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 that, the execution of your view remains where it was, because it creates autosave restrictions. When I do not, my gaze usually disappears. In addition, he does not just remove the restrictions from the supervisor, but goes all the way up, as there may be restrictions affecting him in the views of his ancestors.

+58
May 27 '15 at 19:51
source share

You can remove all restrictions in the view by following these steps:

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

EDIT. To remove restrictions for all subzones, use the following extension in Swift:

 extension UIView { func clearConstraints() { for subview in self.subviews { subview.clearConstraints() } self.removeConstraints(self.constraints) } } 
+41
Oct 06 '14 at 4:04
source share

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) } } 
+16
May 21 '15 at 16:26
source share

There are two ways to achieve this, according to Apple's developer documentation.

1. NSLayoutConstraint.deactivateConstraints

This is a convenient method that provides an easy way to deactivate a set of constraints in one call. The effect of this method is similar to setting the isActive property of each constraint to false. As a rule, using this method is more efficient than disabling each restriction individually.

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

2. UIView.removeConstraints ( UIView.removeConstraints for> = iOS 8.0)

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

 // Declaration func removeConstraints(_ constraints: [NSLayoutConstraint])' // Usage yourView.removeConstraints(yourView.constraints) 

hints

Using a Storyboard or XIB can be such an XIB when setting up restrictions, as indicated in your script, you must create IBOutlets for each of them that you want to remove. Despite this, in most cases, Interface Builder creates more problems than it solves.

Therefore, having very dynamic content and different presentation states, I would suggest:

  1. Creating Your Views Programmatically
  2. Tag them and using NSLayoutAnchor
  3. Add every constraint that can be removed later in the array
  4. Clean them every time before applying a 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() } 

Recommendations

  1. NSLayoutConstraint
  2. Uiview
+15
Feb 16 '17 at 2:53 on
source share

the details

  • Xcode 10.2.1 (10E1001), Swift 5

Decision

 import UIKit extension UIView { func removeConstraints() { removeConstraints(constraints) } func deactivateAllConstraints() { NSLayoutConstraint.deactivate(getAllConstraints()) } func getAllSubviews() -> [UIView] { return UIView.getAllSubviews(view: self) } func getAllConstraints() -> [NSLayoutConstraint] { var subviewsConstraints = getAllSubviews().flatMap { $0.constraints } if let superview = self.superview { subviewsConstraints += superview.constraints.compactMap { (constraint) -> NSLayoutConstraint? in if let view = constraint.firstItem as? UIView, view == self { return constraint } return nil } } return subviewsConstraints + constraints } class func getAllSubviews(view: UIView) -> [UIView] { return view.subviews.flatMap { [$0] + getAllSubviews(view: $0) } } } 

using

 print("constraints: \(view.getAllConstraints().count), subviews: \(view.getAllSubviews().count)") view.deactivateAllConstraints() 
+4
Nov 14 '17 at 8:59
source share

I use the following method to remove all restrictions from the view:

.h file:

 + (void)RemoveContraintsFromView:(UIView*)view removeParentConstraints:(bool)parent removeChildConstraints:(bool)child; 

.m file:

 + (void)RemoveContraintsFromView:(UIView *)view removeParentConstraints:(bool)parent removeChildConstraints:(bool)child { if (parent) { // Remove constraints between view and its parent. UIView *superview = view.superview; [view removeFromSuperview]; [superview addSubview:view]; } if (child) { // Remove constraints between view and its children. [view removeConstraints:[view constraints]]; } } 

You can also read this blog post to better understand how this works.

If you need more granular control, I would highly recommend switching to Masonry , a powerful wireframe class that you can use whenever you need to properly handle constraints programmatically.

+2
Mar 28 '15 at 16:33
source share

Fast decision:

 extension UIView { func removeAllConstraints() { var view: UIView? = self while let currentView = view { currentView.removeConstraints(currentView.constraints.filter { return $0.firstItem as? UIView == self || $0.secondItem as? UIView == self }) view = view?.superview } } } 

It is important to go through all the parents, since the restrictions between the two elements belong to common ancestors, so just cleaning the supervisor as described in this answer is not good enough, and you may end up having an unpleasant surprise later.

+1
Dec 15 '16 at 6:52
source share

Based on previous answers (swift 4)

You can use immediate restriction if you do not want to scan entire hierarchies.

 extension UIView { /** * Deactivates immediate constraints that target this view (self + superview) */ func deactivateImmediateConstraints(){ NSLayoutConstraint.deactivate(self.immediateConstraints) } /** * Deactivates all constrains that target this view */ func deactiveAllConstraints(){ NSLayoutConstraint.deactivate(self.allConstraints) } /** * Gets self.constraints + superview?.constraints for this particular view */ var immediateConstraints:[NSLayoutConstraint]{ let constraints = self.superview?.constraints.filter{ $0.firstItem as? UIView === self || $0.secondItem as? UIView === self } ?? [] return self.constraints + constraints } /** * Crawls up superview hierarchy and gets all constraints that affect this view */ var allConstraints:[NSLayoutConstraint] { var view: UIView? = self var constraints:[NSLayoutConstraint] = [] while let currentView = view { constraints += currentView.constraints.filter { return $0.firstItem as? UIView === self || $0.secondItem as? UIView === self } view = view?.superview } return constraints } } 
+1
May 05 '18 at 12:13
source share

With the aim of

 [self.superview.constraints enumerateObjectsUsingBlock:^(__kindof NSLayoutConstraint * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSLayoutConstraint *constraint = (NSLayoutConstraint *)obj; if (constraint.firstItem == self || constraint.secondItem == self) { [self.superview removeConstraint:constraint]; } }]; [self removeConstraints:self.constraints]; } 
+1
Feb 23 '19 at 7:22
source share

You can use something like this:

 [viewA.superview.constraints enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLayoutConstraint *constraint = (NSLayoutConstraint *)obj; if (constraint.firstItem == viewA || constraint.secondItem == viewA) { [viewA.superview removeConstraint:constraint]; } }]; [viewA removeConstraints:viewA.constraints]; 

This basically lists all viewA view restriction and removes all viewA related restrictions.

Then the second part removes the constraints from viewA using an array of view constraints.

0
Jan 31 '15 at 20:00
source share

(As of July 31, 2017)

SWIFT 3

 self.yourCustomView.removeFromSuperview() self.yourCustomViewParentView.addSubview(self.yourCustomView) 

Goal c

 [self.yourCustomView removeFromSuperview]; [self.yourCustomViewParentView addSubview:self.yourCustomView]; 

This is the easiest way to quickly remove all restrictions that exist in a UIView. Just remember to add the UIView back with new restrictions or a new frame after this =)

0
Jul 06 '17 at 19:53 on
source share

This is a way to disable all restrictions from a specific view.

  NSLayoutConstraint.deactivate(myView.constraints) 
-one
Mar 19 '18 at 8:37
source share



All Articles