What happens with constraints when a view is removed - ios

The question I have is simple but I couldn't find any information in the documentation.
What happens with layout constraints when a view is removed from the view hierarchy (or moved to another view)?
For example, let's have container C with subviews A and B. Container C holds some constraints. Then we call [A removeFromSuperview]. What happens with the constraints for A?
What then happens if we add A to C again?

The constraints are removed. If you add A again, you will have to make new constraints for it, or if you save the constraints before you remove A, you can add them back. When I do something like this, I save the constraints like this for a view called view1:
self.portraitConstraints = [NSMutableArray new];
for (NSLayoutConstraint *con in self.view.constraints) {
if (con.firstItem == self.view1 || con.secondItem == self.view1) {
[self.portraitConstraints addObject:con];
}
}

Since I had this question too, I checked the Apple Docs just for kicks, and it turns out that it is documented that the constraints are removed.
The documentation for the UIView removeFromSuperview method states:
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.
I'm not sure if this was documented last year when the original question was posted, but I just thought I'd share this information in case anyone needed it...

Be aware though, that if you have two independent parent views A and B, and a subview C, where C is currently a subview of A, with appropriate constraints, that calling [B addSubview:C] will NOT clear any constraints relating to A and C, and auto layout will start throwing exceptions, because those constraints no longer relate to views in the same hierarchy.
You will need to call [C removeFromSuperview] explicitly to remove the constraints, before adding C to B.
This is true on Mac OS X - I haven't checked iOS

The constraints are also removed when you [A removeFromSuperview]
They are forgotten and adding A to C again adds no constraints.

They are removed too, you can do a simple test. Pick up a view SUBVIEW and create costraints that constraint SUBVIEW to follow its superview resizing (like attched to to superview edges). To do that you add SUBVIEW as a subview to this CONTAINERVIEW and add as constraints something like that:
V:|-[SUBVIEW]-|
H:|-[SUBVIEW]-|
These constraints should be added to SUBVIEW superview, thus CONTAINERVIEW.
If you remove SUBVIEW by simply checking all the CONTAINERVIEW constraints you could see that two aren't around anymore.

This question also can be proved by interface builder. When drag and drop a UIView on the ViewController add constraints then remove the UIView, you can see the blue constraints disappear.

Related

How to add a UIView as SuperView(background View) to already existed UI elemets with contraints

firstly I have Placed 3 labels in the xib file and I added constraints to the elements(using the Auto layout in storyboard), next I got the requirement to add an image to its background so to do this first I need to remove those constraints after that I added UIImageView and finally need to set constraints to all UI elements but if I have more UI elements with more constraints its more difficult to remove constraint and adding view how to solve this issue
Sometimes its hard to implement when information is poor when you begin. To solve this particular problem, you could have a transparent container view. Just make UIView, place your Elements on it and add constraints. When you now have to add another view behind it, you just have to remove the constraints from the container. Makes things easier.
Another thing is, you can leave those constraints as they are. They refer to the view you have put the Elements in. When you now add another view behind them, you just can add constraints to this new view and the other elements are not affected.
Hope that halps a bit!

addSubview breaking internal contraints

I'm having some trouble with dynamically adding subviews to each other. Namely, when I have a view with constraints built in the interface builder and then use [view addSubview:subview], it destroys all of the constraints that I have set up.
I've tried adding [subview setAutoresizingMask:NO]; as well as subview.translatesAutoresizingMaskIntoConstraints = false;
I expected that the subview's constraints to its original parent would be broken, and added them back in programmatically after my call to addSubview, but I didn't expect that the constraints of its children would also be broken.
Unfortunately, adding back in child constraints is not feasible. The architecture we're using is a plugin model, and while it's simple enough to resize the plugin's container from the main UIViewController, the plugin needs to be responsible for positioning its internal elements.
Here's a mock up of how things should look:
And here's what it currently looks like:
How can I get addSubview to maintain those internal constraints? The red, green, and blue boxes are only constrained to each other and their parent (purple), which are all brought through with addSubview.
I tried too many ways includes sizeToFit()and setting the translatesAutoresizingMaskIntoConstraints but it did not work. You should set width of the custom view which you want to add as subview and you should set the view's sizeToFit(). it worked for me:
bigView.sizeToFit()
subView.sizeToFit()
subView.width = screenWidth
bigView.addSubview(subView)

Constraint changes of super view not reflecting in sub views

Objective:
I have 4 views arranged one below the other. The views also consists of subViews. Suppose the views are named say A, B, C and D in the order they are arranged. At a time, I need to show only, either B or C.
Implementation:
Used autolayout to add respective constraints via storyboard.
Created NSLayoutConstraint outlets for Height constraints of views B and C.
Changed the constant property of the constraint outlet when required, say as follows:
_heightConstraintOfC.constant = ORGINAL_VALUE_OF_C;
_heightConstraintOfB.constant = 0.00;
and
_heightConstraintOfB.constant = ORGINAL_VALUE_OF_B;
_heightConstraintOfC.constant = 0.00;
What I Get:
The views are behaving as expected, But when I change the height constant to zero, the subviews remain in the same position, behind the new overlapped view.
In the screen shot, Login button lies within view B, but is visible, even though view C overlaps it.
What I Tried:
I tried hiding the views , i.e. hide B when showing C. This works, but doesn't seem to be the right way when using autolayout.
I also tried using
[self.view layoutIfNeeded], [self.view layoutSubviews] and [self.view setNeedsLayout]. This didn't help.
What I understand is that you need to add constraints to everything within a view and then update each of them manually. This doesn't seem feasible to me.
Please provide your valuable suggestions or a solution to this problem. Thanks!

hide a view and remove blank spaces

I'm developing an app for iOS and I'm using the Storyboard with AutoLayout ON. One of my view controllers has a set of 3 labels, and in certain circumstances i would like to make the second one disappear.
If I use the setHidden:TRUE method the label become invisible but it still obviously take space in the view.
can someone point me to the right direction?
The simplest solution is to put the views that you want to hide inside a StackView. Then to hide the element simply make it hidden:
_myElement.hidden = YES;
StackView will squash hidden elements and they will become invisible.
I think you can link the constraint with the header file of your viewController. Then modify the constraint and commit changes.
Edited:
1) Create the IBOutlet for the constraint.
2) Modify the constraint, for example: self.yourConstraint.constant = 0.0;
3) Commit the new constraint: [viewForUpdate setNeedsUpdateConstraints];
The easiest and most effective way to handle this is using Stack Views. Insert the label in a horizontal/vertical (orientation they appear on your UI) stack view and stack view will internally take care of the spacing. Additional properties like alignment, spacing can be tweaked as per requirement. Make sure you re-establish the constraints between stack view and adjacent elements because once the views are added to a stack view all if its constraints are cleared
You will need to move the other views by adjusting their frames. This can be done directly, or if using auto layout, by giving them a vertical spacing constraints to the view being hidden.
If there are many other views that depend on the hiding/showing view, create another subview that contains all of the dependent views. The dependent views can layout statically on that parent, and that parent can have it's frame adjusted (again, either directly or via auto layout).
view
|
--- view to hide
|
--- common parent (move this with auto layout or directly)
|
--- subview's with position dependent on view to hide
--- ...
This is a late answer/solution, but I have just built a category which does just that - hiding the view without blank spaces.
https://github.com/neevek/UIView-Visibility

how to change components in UIViewController on runtime while using auto layout in iOS

I have a case in which I need to manipulate UIViewController's component on runtime. The matter is I have adopted Auto Layout.
Now say I have a UIView called aView with Constraints plotted in a UIViewController.
Next, on the basis of my business logic, I need to remove aView and replace with other UIView called bView.
Here, when I remove aView, will all related constraints also removed OR it will remain as it is.
The question is if I simply remove aView and add bView will plot UIView same as before with old constraints or I need to re-implement all constraints?
Which is the best approach to change UIViews on runtime, considering using Auto Layout?
When you remove aView and replace with bView the constraints will be gone and you will have to add them again. You can't take the constraints that belonged to aView and apply them to bView, you'll have to recreate them for bView.
It might be possible for you to skip autolayout for bView completely if it is just going to take the place of aView. If, in this case, the layout system has run and found a frame for aView you can just reuse that frame for bView.
It might be simpler to just add both aView and bView when the viewController loads and then switch one or the other to be hidden.
Why don't you just create a public method for the constraint programmatically, and just need to call the method for each time you create a new viewcontroller rather than copy and paste the method. Other solution is, creating a superclass of all the uiview that you want to have the same constraint.

Resources