Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change label constraints during runtime?

I have a table view and a cell inside it. The cell contains three labels: header label and two labels below one to each other. Sometimes, I need to hide those two labels below if they do not contain data and change "Top space to container" of "Header label" to "Center Y to container". And of course revert the constraints back when two labels contain data. Here's a screenshot of simple demo project just for showing the idea:

enter image description here

UPDATE Max MacLeod answer pointed to right direction. The trick is to push header label down when first and second labels are hidden. So we need to set bottom space to container view for first and second labels instead of creating top space to container view for header label. And hiding/unhiding should be done by having height outlets (height constraints for first and second label) and setting their constant values to zero (and setting back value when unhiding). I also uploaded the source code example to Github.

like image 913
Centurion Avatar asked Oct 31 '13 13:10

Centurion


2 Answers

Select the header label, and one of the lower labels, and add a new vertical space constraint reflecting the gap between them. Next, remove the header label Top space to container constraint. Maybe you already have this (can't quite see from the screen grab). If you do, that's good.

Now, create two height constraints for each lower label. IBOutlet those to your class.

Then, hide those two lower labels whenever you need to by setting each height constraint's constant to 0.f.

That will render them invisible and lower the header label above so that it is now vertically centered Y in the container.

Will go through the steps once more (was too long for a comment!). Sequence matters with IB as first you must add a new constraint before you can delete the old one. Temporarily you will have one superfluous constraint. It's because IB won't allow ambiguity. So, first add the new vertical space constraint. That will define the Y position of the upper label. Then, remove the superfluous vertical space to container constraint from the upper label. Now that label will be Y positioned using the vertical space relative to the lower labels. Next, add the height constraints for each lower label and link to the class with an IBOutlet. One other thing, actually you will need the lower labels to be constrained to the container with a bottom space constraint. When their height is reduced to zero, they will disappear, and the upper label will move lower to assume the Y center position.

To revert, just set the constant back to the original value.

This is a much better approach than adding/removing constraints, which is a heavyweight operation. Note that you may wish to add the two lower labels to a "container" view, so that they can be shown/hidden as one. Also, it would tidy the code as you really want the vertical space to be between your upper label, and both lower labels rather than just one.

See also my answer AutoLayout with hidden UIViews?

like image 200
Max MacLeod Avatar answered Nov 14 '22 11:11

Max MacLeod


Put the labels you want to hide into a view, once everything has the correct layout constraints, add a height constraint to the container view, and connect the constraint into an IBOutlet property.

Make sure that your properties are strong

in code yo just have to set the constant to 0 and activate it, tho hide the content, or deactivate it to show the content. This is better than messing up with the constant value an saving-restoring it. Do not forget to call layoutIfNeeded afterwards.

@property (strong, nonatomic) IBOutlet UIView *myContainer;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *myContainerHeight; //should be strong!!

-(void) showContainer
{
    self.myContainerHeight.active = NO;
    self.myContainer.hidden = NO;
    [self.view layoutIfNeeded];
}
-(void) hideContainer
{
    self.myContainerHeight.active = YES;
    self.myContainerHeight.constant = 0.0f;
    self.myContainer.hidden = YES;
    [self.view layoutIfNeeded];
}

Once you have your setup you can test it in IntefaceBuilder by setting your constraint to 0 and then back to the original value. Don't forget to check other constraints priorities so when hidden there is no conflict at all. other way to test it is to put it to 0 and set the priority to 0, but, you should not forget to restore it to the highest priority again.

like image 8
Jorge Arimany Avatar answered Nov 14 '22 11:11

Jorge Arimany