1

Let's say I have a parent view which contains several subviews. Using auto layout I want to set the parent view's height constraint to 0 and I want that all of the subviews of the parent view will have the same height constraint as the parent view.

This will greatly help me when I want to hide a view and all of its subviews without changing directly their constraints(without adding/removing constraints).

Currently my solution to my problem is changing all of the subviews height constraint to zero when the parent view is hidden and when the parent view is shown update all of the subviews to their original height. (I've a nice trick for UILabel where number of lines is equal to 0; instead of setting its height constraint, I simply change its content; when I want to hide the label I simply set the text to an empty string @"", this actually set the height to 0 as there is no text. When I want to show the label I simply change its content to what ever I want to display).

kernix
  • 7,970
  • 3
  • 28
  • 44
  • Why just you don't connect height constraint to IBOutlet and set it in code? – Nikita Took Mar 11 '14 at 14:05
  • If you want to hide, why not animate a move off screen instead of squashing? – Wain Mar 11 '14 at 14:09
  • @NikitaTook I'm talking about that exactly, but instead of changing the height constraint to all of the parent's subviews, I want to set the height constraint of the parent to 0 via the IBOutlet(without setting the height constraint to all of the subviews) – kernix Mar 11 '14 at 14:15
  • @Wain, I think it is the easiest way for me to maintain my code. I'm writing a custom UICollectionViewCell which has few views that sometime appear and sometimes not. – kernix Mar 11 '14 at 14:19
  • @Vinzzz, I've tried setting height constraint to the parent view and change its height constraint to 0 or its original height. I've tried to add top and bottom constraint from the subview to their parent view with lower than or equal constraint, and also lowered content hugging and content compression resistance priority to 1. Unfortunately I've not come up with a good plan other than changing all of the subviews height constraints to 0 (which is possible but I hope there is a more elegant solution). – kernix Mar 11 '14 at 14:37

3 Answers3

1

If I understand what you are asking correctly, I think you just need to have 2 height constraints for each of your subviews.

The first will be a height constraint with a constant of whatever you want the height to be when the parent view is shown, and set the priority to less than 1000 (I've been using 800, and it seems to work for what I want). This is the constraint that will be applied when the superview's height is NOT 0.

The second height constraint will have a constant >= 0, and will have a priority of 1000. This will be the constraint that will get applied when the superview height = 0.

EDIT: To get the height of a view for the priority 800 constraint, you can either:

Storyboard:

Set up the view with whatever content you want it to have. So for a label, set the number of lines, font size, etc., put in some text (it doesn't have to be exactly the text the user will see - your code will probably be changing myLabel.text somewhere anyway. After the label is set up, click the "Pin" constraints button at the bottom right of the window, and the height should be auto-populated. Apply the constraint, and then edit the constraint after it has been created to lower the priority.

Code:

Setup the label's font, number of lines, and everything else like in the Storyboard approach, and add some dummy text again. Then, you can ask the label how much height it wants to display the dummy text you've given it by calling [myLabel sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)].height


EDIT 2:

Okay, this is a little different than I had before. Let's try some screenshots and code snipets. These are just from a quick test project I put together, but you should be able to expand the idea to what you are working on.

In the storyboard, setup your horizontal constraints for your superview (green background) and for the location of the top of the superview.

enter image description here

Then, add a height constraint for the expanded height. Set the Priority of this constraint to High (750).

enter image description here

Then, add your subviews to the superview. Add constraints for the subviews as if everything was normal and nothing was going to be happening to the superview. The only difference is you want to set .hidden to YES by default (otherwise if the view starts collapsed the subviews will be visible and the spacing will be all funky). Note that for the multi-line label, I don't specify a height constraint - XCode will figure that out for itself based on the text I put in it.

enter image description here

Lastly, add a second height constraint to the superview, with a constant = 0 and a priority 1000.

enter image description here

Now the little bit of Code:

In the .h file for the view controller, set up IBOutlets for the superview and for the height = 0 constraint of the view.

MyViewController.h

#import <UIKit/UIKit.h>

@interface MyViewController : UIViewController
{
    IBOutlet NSLayoutConstraint *superHeighConstraint;
    IBOutlet UIView *myCollapsibleView;
}

@end

For testing, I added a UISegmentedControl that will toggle if the superview is collapsed or not. Here is the code that responds to changes in selection:

MyViewController.m

...

- (IBAction)segmentUpdated:(UISegmentedControl *)sender
{
    if ([sender selectedSegmentIndex] == 0)
    {
        [myCollapsibleView removeConstraint:superHeighConstraint];
        for (UIView *subview in [myCollapsibleView subviews])
        {
            [subview setHidden:NO];
        }
    }
    else if ([sender selectedSegmentIndex] == 1)
    {
        [myCollapsibleView addConstraint:superHeighConstraint];
        for (UIView *subview in [myCollapsibleView subviews])
        {
            [subview setHidden:YES];
        }
    }
}

With this setup, you are never changing any of the constraints in the code - you are just choosing when to apply or not apply the height = 0 constraint of the superview. Looping through [myCollapsibleView subviews] makes it easy to show/hide the subviews as needed, and it is done dynamically, so if you add or remove subviews later, you don't have to touch the code.

Simulator Pics:

Load: enter image description here

Toggle show: enter image description here

Toggle hide: enter image description here

GeneralMike
  • 2,951
  • 3
  • 28
  • 56
  • hmm... what if my subview is a UILabel and number of rows is 0? then I don't know what its height. – kernix Mar 11 '14 at 14:25
  • Hm, not sure I understand your question. Do you mean the number of lines in the label is 0? Then the height would obviously be 0 - but I don't think that's what you mean. If you are talking about a standard `UILabel` with 1 line and standard font, the height is 21. If you have multiple lines or nonstandard font, then you can take care of that either on your storyboard or in the code - see my edit. – GeneralMike Mar 11 '14 at 14:32
  • in UILabel, number of lines = 0 means that the number of lines is dynamic and can range 0-n lines(it doesn't mean of course that the height is 0). – kernix Mar 11 '14 at 14:34
  • Ah, I didn't realize that the number of lines could be dynamic. I would suggest looking into the priorities a little deeper in that case - there should be an automatically generated constraint that sets the height based on how much space it needs to display the content. That constraint may end up being a replacement for the first constraint I mentioned in my original answer, but I'm not sure - I haven't had to look that deeply into it before. – GeneralMike Mar 11 '14 at 14:46
  • I don't want to start changing subviews constraints from code; If I wanted to then I've a working solution for that too. My question is whether it's possible to only set parent view height constraint to 0 which will cause all of the subviews to shrink in size. – kernix Mar 11 '14 at 14:48
  • @kernix: see my EDIT 2: – GeneralMike Mar 11 '14 at 18:02
  • thanks for the time answering; I will try this: however, In my question I mentioned I prefer not add/remove constraints as I'm doing this inside UICollectionViewCell which when adding/removing consraints is a performance penalty. – kernix Mar 11 '14 at 18:24
0

A slightly different approach may be to just use setHidden: to make things appear and disappear as needed. This is much easier to implement than programmatically playing with constraints, but can sometimes result in ugly blank spaces in strange places. I'm not sure if it will work for your particular layout or not, but I thought it was worth mentioning.

GeneralMike
  • 2,951
  • 3
  • 28
  • 56
0

Good solution here: Hide autolayout UIView : How to get existing NSLayoutConstraint to update this one

Use a category to update constraints already created.

Community
  • 1
  • 1
Damien Romito
  • 9,801
  • 13
  • 66
  • 84