IOS adds constraint to table section header
I am working with a grouped table and setting the header in the sections using the tableView: viewForHeaderInSection: method and setting the height using tableView: heightForHeaderInSection :.
I created a view and put a shortcut in it like this:
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
// Create a custom title view.
UIView *ctv;
UILabel *titleLabel;
// Set the name.
{...} // Code not relevant
// If an iPhone.
if ([Config isPhone]) {
ctv = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 14, 320, 36)];
}
// If an iPad
else {
ctv = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 768, 75)];
titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 544, 55)];
}
// Config the label.
{...} // Code not relevant
// Center the items.
ctv.center = CGPointMake(tableView.center.x, ctv.center.y);
titleLabel.center = ctv.center;
// Add the label to the container view.
[ctv addSubview:titleLabel];
// Return the custom title view.
return ctv;
}
This all works great until you rotate the screen. Off position. I understand that this is because the viewpoint is centered while it is in a different orientation, resulting in the center being calculated no longer being correct. The solution should be to add a constraint. I tried to add the constraint below:
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(ctv);
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|[ctv]|"
options:0
metrics:nil
views:viewsDictionary
];
[tableView addConstraints:constraints];
But when I do this while trying to use the method below, I realize that there is no parent view associated with it, which makes full sense, because it is not technically being added to the view. So I thought I'd try to add a constraint like this:
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:ctv
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:tableView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0
];
[tableView addConstraint:constraint];
But these are also mistakes. I tried to switch the tableView variables to the global table property, but it gives the same results. I also tried to figure out how to add a constraint in the view, loaded the method, but it failed as I couldn't figure out how to get back to the table section headers from the table object. The last thought I had was to set the width of the table in the constraint and set it to the center of the entire table. This process worked, but now I have an ugly scroll in the middle of my application when in landscape orientation. So the question is, where / how can I access the individual section headers after loading them in order to add this constraint? I'm still pretty new to Objective-C, so any help is appreciated.
***** NEW CODE BASED ON rdelmar SUGGESTION ****
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *ctv = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"groupHeader"];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 544, 55)];
[titleLabel setTranslatesAutoresizingMaskIntoConstraints: NO];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:ctv
attribute:NSLayoutAttributeCenterX
relatedBy:0
toItem:titleLabel
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0
];
[ctv addConstraints:@[constraint]];
titleLabel.text = @"string";
[ctv addSubview:titleLabel];
return ctv;
}
But as I mentioned, it gives me the error "Constraint must contain the first element of the layout".
source to share
If you can't get the constraints to work, your source code, padded with an autoresist mask (flexible left and right margins), will do the job.
An even simpler solution would be to return the UILabel as a title with centered text.
Your first attempt at constraints will not work because you configured them incorrectly.
The table view specifies the header view frame. You need to worry about the position of the label within the title. The VFL for this will be "|titleLabel|"
- the header label must be assigned to its super, header view.
source to share
I did this in a recent project to add a shortcut and UIActivityIndicatorView:
-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:@"Header"];
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0,0, 250, 20)];
[label setTranslatesAutoresizingMaskIntoConstraints:NO];
NSLayoutConstraint *con1 = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:label attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
NSLayoutConstraint *con2 = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeLeft relatedBy:0 toItem:label attribute:NSLayoutAttributeLeading multiplier:1 constant:-10];
[headerView addConstraints:@[con1,con2]];
label.text = @"Pick an Activity from the List";
label.backgroundColor = [UIColor clearColor];
[headerView addSubview:label];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[spinner setTranslatesAutoresizingMaskIntoConstraints:NO];
if (activityIndicatorShouldStop == NO) [spinner startAnimating];
[headerView addSubview:spinner];
NSLayoutConstraint *con3 = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:spinner attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
NSLayoutConstraint *con4 = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeRight relatedBy:0 toItem:spinner attribute:NSLayoutAttributeTrailing multiplier:1 constant:10];
[headerView addConstraints:@[con3,con4]];
return headerView;
}
source to share