Setting a label to UITableView's tableFooterView - with autolayout
Solution 1
You shouldn't set translatesAutoresizingMaskIntoConstraints to NO for table views, their cells, or table header and footer views (or for your controller's self.view for that matter). It's ok to use constraints for views inside those views (the content view of cells or the header and footer views). I added a simplified version of your code to viewDidLoad, and it worked as expected. Note that you need to give the footer view a height and an x position (the y position and the width are ignored),
UIView *tempFooter = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 50)];
UILabel *atext = [[UILabel alloc] init];
atext.translatesAutoresizingMaskIntoConstraints = NO;
atext.numberOfLines = 0;
[atext setText:@"Add Some Text"];
atext.textAlignment = NSTextAlignmentCenter;
atext.font = [UIFont italicSystemFontOfSize:14];
atext.textColor = [UIColor grayColor];
atext.backgroundColor = [UIColor clearColor];
atext.lineBreakMode = NSLineBreakByWordWrapping;
[tempFooter addSubview:atext];
NSDictionary *dict = NSDictionaryOfVariableBindings(atext);
[tempFooter addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[atext]-10-|" options:0 metrics:nil views:dict]];
[tempFooter addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[atext]|" options:0 metrics:nil views:dict]];
self.tableView.tableFooterView = tempFooter;
I'm not sure what you were trying to accomplish with your constraint, tvatt3. The multiplier (you have 5) doesn't do anything with a top or left constraint since the value of those attributes is 0. I used the visual constraints, rather than the method you used, but when I used your code to add the constraints, it worked also .
Solution 2
Interestingly, changing the Autoresizing mask in the xib solved my problem.
Constraints not working:
Working:
Solution 3
I was able to make dynamically auto layout table footer width and height by implementing @rdelmar solution for constraints and adding these lines below. Same solution applies to table header view.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let tableFooter = tableView.tableFooterView {
let maxSize = CGSize(width: self.tableView.bounds.size.width,
height: CGFloat.greatestFiniteMagnitude)
let size = tableFooter.systemLayoutSizeFitting(maxSize)
let height = size.height
var headerFrame = tableFooter.frame
// If we don't have this check, viewDidLayoutSubviews() will get
// repeatedly, causing the app to hang.
if height != headerFrame.size.height {
headerFrame.size.height = height
tableFooter.frame = headerFrame
tableView.tableFooterView = tableFooter
}
}
}
P. S. I prefer Interface Builder for constraints setup
Comments
-
Z S almost 2 years
When my table view is empty, I want to add a simple label into the tableview footer to display a "no content" message. It was working fine when I was setting the frames of the UILabel and the UIView that I used for footerView, but now I'm trying to convert to using auto-layout, and I can't get it to work.
Here's what I'm doing:
// Create the footer UIView *tempFooter = [[UIView alloc] init]; UILabel *atext = [[UILabel alloc] init]; tempFooter.translatesAutoresizingMaskIntoConstraints = NO; atext.translatesAutoresizingMaskIntoConstraints = NO; atext.numberOfLines = 0; [atext setText:@"Add Some Text"]; atext.textAlignment = NSTextAlignmentCenter; atext.font = [UIFont italicSystemFontOfSize:14]; atext.textColor = [UIColor grayColor]; atext.backgroundColor = [UIColor clearColor]; atext.lineBreakMode = NSLineBreakByWordWrapping; // add label to footer view, and add constraints [tempFooter addSubview:atext]; NSLayoutConstraint *tvatt1 = [NSLayoutConstraint constraintWithItem:tempFooter attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:atext attribute:NSLayoutAttributeLeft multiplier:1.0 constant:10.0]; NSLayoutConstraint *tvatt2 = [NSLayoutConstraint constraintWithItem:tempFooter attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:atext attribute:NSLayoutAttributeRight multiplier:1.0 constant:10.0]; NSLayoutConstraint *tvatt3 = [NSLayoutConstraint constraintWithItem:tempFooter attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:atext attribute:NSLayoutAttributeTop multiplier:5.0 constant:0]; NSLayoutConstraint *tvatt4 = [NSLayoutConstraint constraintWithItem:tempFooter attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:atext attribute:NSLayoutAttributeBottom multiplier:1.0 constant: 0]; [tempFooter addConstraints: @[tvatt1, tvatt2, tvatt3, tvatt4]]; // set the footerview self.tview.tableFooterView = tempFooter;
When I run this, I get a crash:
2014-09-08 19:57:16.594 SimpleList[49442:60b] * Assertion failure in -[UITableView layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2935.137/UIView.m:8794 2014-09-08 19:57:21.073 SimpleList[49442:60b] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super
I'm not sure what I'm doing wrong. I've also tried setting constraints for the
self.tview.tableFooterView
wrt thetempFooter
(pinning against all 4 sides) but that doesn't change the crash. I also call:[self.tview.tableFooterView layoutSubviews];
but that doesn't help either.
Any ideas what I'm doing wrong?
-
Z S over 9 yearsThanks, but the question is more about a UITableView's tableFooterView. The general use-case of adding a view into another UIView is simple enough.
-
Z S over 9 yearsThanks. The multiplier by 5 is a typo (it should be 1). This seems to work, but there is a major problem, this is that the height is fixed at 50. How do I adjust the header height if the text is much longer? e.g. try with this:
[atext setText:@"Add Some Text. Now add a lot more text with newlines thrown in for good measure. Does this work beyond a certain height?\n\nNow how do you calculate the height?"];
The full footer doesn't show anymore. I've tried using[atext systemLayoutSizeFittingSize: UILayoutFittingExpandedSize]
to set the frame for footer before setting it, but it crashes -
Z S over 9 yearsI thinkk I have it working; I set the footerView in
viewWillLayoutSubviews
and set the height of the footer usingsystemLayoutSizeFittingSize:
. The only problem: still getting a "Unable to simultaneously satisfy constraints" message in the debugger. This one looks suspicious, but no idea how it got there: "<NSLayoutConstraint:0x7fa2d0050d20 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7fa2d005acb0(0)]>" -
Z S over 9 yearsFigured it out: the visual constraint for pinning the label horizontally wasn't working. I removed that and added a centering constraint with constraintWithItem between label and tempFooter (with NSLayoutAttributeCenterX) and it works!
-
Anurag Bhakuni over 9 years@ZS explore this link(constraints.icodeforlove.com) , might it help you in some way.
-
Lorenzo B over 8 yearsCan you explain why the translatesAutoresingMaskIntoConstraints should not be set? Thanks
-
Evan R almost 8 years@rdelmar "Note that you need to give the footer view a height and an x position (the y position and the width are ignored)"—actually, under iOS 9 at least, the width passed in isn't ignored and is used to set the width of the view.
-
ishegg about 5 yearsAfter literal hours of trying different things, this fixed my problem for both the footer and header views of a
UITableView
. Thank you so much! I would never have thought of this.