Chenya Zhang Chenya Zhang - 7 months ago 55
iOS Question

UITableViewController Table Header Add a UIButton with Autolayout Constraints

I try to add a UIButton to a UITableHeaderFooterView.

It seems that I can only use specific CGRect frame to pin its position and size in code (<-- did a lot of search on StackOverFlow). And the position is very hard to control, always flying around.

UIButton *scanQRCodeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
scanQRCodeButton.frame = CGRectMake(0.0f, 5.0f, 320.0f, 44.0f);
scanQRCodeButton.backgroundColor = [UIColor redColor];
[scanQRCodeButton setTitle:@"Hello" forState:UIControlStateNormal];
[cell addSubview:scanQRCodeButton];

But what I really want is to use "constraints" like centerX, centerY and proportional width to make it adaptive to different screen size. Then the problem comes with the part "constraintWithItems":

Get the headerView from UITableView:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
static NSString *headerReuseIdentifier = @"TableViewSectionHeaderViewIdentifier";

// Reuse the instance that was created in viewDidLoad, or make a new one if not enough.
UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
if (headerView == nil) {
[tableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"TableViewSectionHeaderViewIdentifier"];
headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"TableViewSectionHeaderViewIdentifier"];

headerView.textLabel.text = @"MISSION";
headerView.contentView.backgroundColor = [UIColor blackColor];

Create the UIButton on top of the headerView in the same block as above:

UIButton *goBack = [[UIButton alloc] init];
[goBack setImage:[UIImage imageNamed:@"Back"] forState:UIControlStateNormal];
[goBack addTarget:self

[headerView addSubview:goBack];

Then set the constraints and return the headerView:

NSLayoutConstraint *constraint = [NSLayoutConstraint
[headerView addConstraint:constraint];
return headerView;

Problem: when I say "headerView.goBack" in "constraintWithItem", the compiler warns me that "Property goBack not found on object of type UITableHeaderFooterView".

Update 1

From Natarajan's answer, I try to do this now:

headerView.translatesAutoresizingMaskIntoConstraints = false;
goBack.translatesAutoresizingMaskIntoConstraints = false;
NSDictionary *metrics = @{ @"width" : @(CGRectGetWidth(self.view.frame) / 10) };
[headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[goBack]|" options:0 metrics:metrics views:@{@"goBack":goBack}]];
[headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[goBack]|" options:0 metrics:metrics views:@{@"goBack":goBack}]];

Current Problem: The "metrics" part does not work. I want to have proportional width to the headerView or tableView instead of fixed numbers. Should I use "self.view.frame" (also tried self.tableView.frame)?


Complier warning is correct as UITableViewHeaderFooterView doesn't have the property named "goBack" which you have just added as a subview of UITableViewHeaderFooterView. So Just try to pass the "goBack" button in your constraint code as like below.

To set goBack button fully occupied on HeaderView:

[headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[goBack]|" options:0 metrics:nil views:@{@"goBack":goBack}]];

[headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[goBack]|" options:0 metrics:nil views:@{@"goBack":goBack}]];

To set goBack button for specific width and height:

[headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[goBack(40.0)]" options:0 metrics:nil views:@{@"goBack":goBack}]];

[headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[goBack(30.0)]" options:0 metrics:nil views:@{@"goBack":goBack}]];

Note: Before adding constraint don't forgot to set the headerView.translatesAutoresizingMaskIntoConstraints = false; and goBack.translatesAutoresizingMaskIntoConstraints = false;