Search code examples
iosuitableviewios7autolayout

UITableViewController: programmatically autolayout bug on iOS 7


I want to have a UIView programmatically added to a UITableViewController which is using autolayout...

I have the following code inside of the viewDidLoad of a UITableViewController:

UIView *centerView = [[UIView alloc] init];
[centerView setTranslatesAutoresizingMaskIntoConstraints:NO];
centerView.backgroundColor = [UIColor greenColor];
[self.view addSubview:centerView];

// Width constraint, half of parent view width
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                              attribute:NSLayoutAttributeWidth
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:self.view
                                                              attribute:NSLayoutAttributeWidth
                                                             multiplier:0.5
                                                               constant:0]];

// Height constraint, half of parent view height
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                              attribute:NSLayoutAttributeHeight
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:self.view
                                                              attribute:NSLayoutAttributeHeight
                                                             multiplier:0.5
                                                               constant:0]];

// Center horizontally
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                              attribute:NSLayoutAttributeCenterX
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:self.view
                                                              attribute:NSLayoutAttributeCenterX
                                                             multiplier:1.0
                                                               constant:0.0]];

// Center vertically
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                              attribute:NSLayoutAttributeCenterY
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:self.view
                                                              attribute:NSLayoutAttributeCenterY
                                                             multiplier:1.0
                                                               constant:0.0]];

If I now run the app on iOS 8 all working well:

running on iOS 8


If I run it on iOS 7, the app crashes with the following error:

*** Assertion failure in -[UITableView layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2935.137/UIView.m:8794

If I set setTranslatesAutoresizingMaskIntoConstraints to YES, the app crashes as well with this notice: Unable to simultaneously satisfy constraints


Solution

  • Okay, it looks like UITableView doesn't support Autolayout on iOS 7. So we have to use autoresizing masks. My idea is to put a containerView with autoresizing mask as the tableview's subview and inside that your centerView:

    Code:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        [self setupBackgroundView];
    }
    
    - (void)setupBackgroundView
    {
        UIView *backgroundContainerView = [[UIView alloc] initWithFrame:CGRectZero];
        backgroundContainerView.backgroundColor = [UIColor cyanColor];
        backgroundContainerView.frame = self.tableView.bounds;
        backgroundContainerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
        [self.view addSubview:backgroundContainerView];
    
    
        UIView *centerView = [[UIView alloc] initWithFrame:CGRectZero];
        centerView.translatesAutoresizingMaskIntoConstraints = NO;
        centerView.backgroundColor = [UIColor greenColor];
    
        [backgroundContainerView addSubview:centerView];
    
        [backgroundContainerView addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                                            attribute:NSLayoutAttributeWidth
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:backgroundContainerView
                                                                            attribute:NSLayoutAttributeWidth
                                                                           multiplier:0.5
                                                                             constant:0]];
    
        // Height constraint, half of parent view height
        [backgroundContainerView addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                                            attribute:NSLayoutAttributeHeight
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:backgroundContainerView
                                                                            attribute:NSLayoutAttributeHeight
                                                                           multiplier:0.5
                                                                             constant:0]];
    
        // Center horizontally
        [backgroundContainerView addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                                            attribute:NSLayoutAttributeCenterX
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:backgroundContainerView
                                                                            attribute:NSLayoutAttributeCenterX
                                                                           multiplier:1.0
                                                                             constant:0.0]];
    
        // Center vertically
        [backgroundContainerView addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                                            attribute:NSLayoutAttributeCenterY
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:backgroundContainerView
                                                                            attribute:NSLayoutAttributeCenterY
                                                                           multiplier:1.0
                                                                             constant:0.0]];
    
    }
    

    Now centerView moves when the table view gets scrolled. If you want to have it fixed and the content hovering above, you should use backgroundView on UITableView:

    - (void)setupBackgroundView
    {
        UIView *backgroundContainerView = [[UIView alloc] initWithFrame:CGRectZero];
        backgroundContainerView.backgroundColor = [UIColor cyanColor];
    
        UIView *centerView = [[UIView alloc] initWithFrame:CGRectZero];
        centerView.translatesAutoresizingMaskIntoConstraints = NO;
        centerView.backgroundColor = [UIColor greenColor];
    
        [backgroundContainerView addSubview:centerView];
    
        [backgroundContainerView addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                                            attribute:NSLayoutAttributeWidth
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:backgroundContainerView
                                                                            attribute:NSLayoutAttributeWidth
                                                                           multiplier:0.5
                                                                             constant:0]];
    
        // Height constraint, half of parent view height
        [backgroundContainerView addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                                            attribute:NSLayoutAttributeHeight
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:backgroundContainerView
                                                                            attribute:NSLayoutAttributeHeight
                                                                           multiplier:0.5
                                                                             constant:0]];
    
        // Center horizontally
        [backgroundContainerView addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                                            attribute:NSLayoutAttributeCenterX
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:backgroundContainerView
                                                                            attribute:NSLayoutAttributeCenterX
                                                                           multiplier:1.0
                                                                             constant:0.0]];
    
        // Center vertically
        [backgroundContainerView addConstraint:[NSLayoutConstraint constraintWithItem:centerView
                                                                            attribute:NSLayoutAttributeCenterY
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:backgroundContainerView
                                                                            attribute:NSLayoutAttributeCenterY
                                                                           multiplier:1.0
                                                                             constant:0.0]];
    
        self.tableView.backgroundView = backgroundContainerView;
    
    }