1

I'm trying to use the usual method of removing a label and have autolayout adjust everything. How to change label constraints during runtime. However, I am doing it in a UITableView header.

UITableView header

When I set the height constraint of one of the labels:

self.labelAHeight.constant = 0;

The result is:

Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1)
look at each constraint and try to figure out which you don't expect; (2) find the code that added 
the unwanted constraint or constraints and fix it. (Note: If you're seeing 
NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the 
UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0xb0faad0 V:[UILabel:0xb0fa830(0)]>",
    "<NSLayoutConstraint:0xb0772a0 V:[UILabel:0xb077300(58)]>",
    "<NSLayoutConstraint:0xb076cc0 V:|-(0)-[UILabel:0xb0fa830]   (Names: '|':UIView:0xb077660 )>",
    "<NSLayoutConstraint:0xb076c90 V:[UILabel:0xb077300]-(0)-|   (Names: '|':UIView:0xb077660 )>",
    "<NSLayoutConstraint:0xb076c00 V:[UILabel:0xb0fa830]-(0)-[UILabel:0xb077300]>",
    "<NSAutoresizingMaskLayoutConstraint:0xb06f030 h=--& v=--& V:[UIView:0xb077660(119)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xb0772a0 V:[UILabel:0xb077300(58)]>

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> 
may also be helpful.

I have tried [self.labelA setTranslatesAutoresizingMaskIntoConstraints:NO] which does not help.

I have tried [self.table.tableHeaderView setTranslatesAutoresizingMaskIntoConstraints:NO] which crashes with *** Assertion failure in -[UITableView layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2935.137/UIView.m:8794. Possibly, I'm doing this in the wrong place (just before setting the constraint constant).

It doesn't seem to matter where the constraint change occurs, e.g. viewDidLoad, or a button handler.

It appears as though the header wants to be a certain height (<NSAutoresizingMaskLayoutConstraint:0xb06f030 h=--& v=--& V:[UIView:0xb077660(119)]> based on its contents) and autolayout gets very unhappy if the contents are changed.

Can anyone help debug this or suggest how to solve it? (I've tried Instruments but was baffled by all the constraints being added and removed...)

Community
  • 1
  • 1
Matt
  • 4,261
  • 4
  • 39
  • 60

1 Answers1

0

The following is a partial answer. It is possible to prevent the constraint issue above, however, I have not found how to make the rest of the table move as the header size changes.

1) Set table header's translatesAutoresizingMaskIntoConstraints = NO in the storyboard.

enter image description here

2) Set constraints on the header now that the autoresizing mask is not contributing constraints.

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.table addConstraint:
             [NSLayoutConstraint constraintWithItem:self.table.tableHeaderView
                                          attribute:NSLayoutAttributeWidth
                                          relatedBy:NSLayoutRelationEqual
                                             toItem:self.table
                                          attribute:NSLayoutAttributeWidth
                                         multiplier:1
                                           constant:0]];
    [self.table addConstraint:
             [NSLayoutConstraint constraintWithItem:self.table.tableHeaderView
                                          attribute:NSLayoutAttributeTop
                                          relatedBy:NSLayoutRelationEqual
                                             toItem:self.table
                                          attribute:NSLayoutAttributeTop
                                         multiplier:1
                                           constant:0]];
}

The result of setting the constant of the height constraint of label A to zero is:

before:

enter image description here

after (it can be seen that the top label has disappeared, but the table rows have not moved up to the bottom of the header):

enter image description here

I have verified that the header view has in fact reduced its height.

I have tried setNeedsLayout and setNeedsDisplay on the header, the table, the view. I have tried beginUpdates and endUpdates around setting the contraint constant. I have tried reloadData. But nothing has worked.

I suspect that the table does not have constraints between the header and the cells.

If anyone has any ideas, I'd be glad to hear them.

EDIT

3) The table can be made to redraw with the following:

self.labelAHeight.constant = 0;
[self performSelector:@selector(reloadHeader) withObject:nil afterDelay:0];

//    [self.table.tableHeaderView setNeedsUpdateConstraints];
//    
//    [UIView animateWithDuration:0.3f animations:^{
//        [self.table.tableHeaderView layoutIfNeeded];
//    }];

and

- (void) reloadHeader {
//    [self.table beginUpdates];
    self.table.tableHeaderView = self.table.tableHeaderView;
//    [self.table endUpdates];
}

Uncommenting the lines above attempts to animate the change, but the animation of the header and the rest of the table are not tied together rigidly, so there can be gaps appearing between the header and table.

Still not perfect, but getting close.

Matt
  • 4,261
  • 4
  • 39
  • 60