Is it possible to use AutoLayout with UITableView's tableHeaderView?

uitableview autolayout programmatically
uitableview dynamic height swift
uitableview height based on number of cells autolayout
uitableview height based on content
uitableviewcell height change dynamically
uitableviewcell dynamic height based on content swift
swift uitableviewcell autolayout
uitableviewcell autolayout rotation

Since I discovered AutoLayout I use it everywhere, now I'm trying to use it with a tableHeaderView.

I made a subclass of UIView added everything (labels etc...) I wanted with their constraints, then I added this CustomView to the UITableView'tableHeaderView.

Everything works just fine except the UITableView always displays above the CustomView, by above I mean the CustomView is under the UITableView so it can't be seen !

It seems that no matter what I do, the height of the UITableView'tableHeaderView is always 0 (so is the width, x and y).

My question : is it possible at all to accomplish this without setting the frame manually ?

EDIT : The CustomView'subview that I'm using has these constraints :

_title = [[UILabel alloc]init];
_title.text = @"Title";
[self addSubview:_title];
[_title keep:[KeepTopInset rules:@[[KeepEqual must:5]]]]; // title has to stay at least 5 away from the supperview Top
[_title keep:[KeepRightInset rules:@[[KeepMin must:5]]]];
[_title keep:[KeepLeftInset rules:@[[KeepMin must:5]]]];
[_title keep:[KeepBottomInset rules:@[[KeepMin must:5]]]];

I'm using a handy library 'KeepLayout' because writing constraints manually takes forever and way too many line for one single constraint but the methods are self-explaining.

And the UITableView has these constraints :

_tableView = [[UITableView alloc]init];
_tableView.translatesAutoresizingMaskIntoConstraints = NO;
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.backgroundColor = [UIColor clearColor];
[self.view addSubview:_tableView];
[_tableView keep:[KeepTopInset rules:@[[KeepEqual must:0]]]];// These 4 constraints make the UITableView stays 0 away from the superview top left right and bottom.
[_tableView keep:[KeepLeftInset rules:@[[KeepEqual must:0]]]];
[_tableView keep:[KeepRightInset rules:@[[KeepEqual must:0]]]];
[_tableView keep:[KeepBottomInset rules:@[[KeepEqual must:0]]]];

_detailsView = [[CustomView alloc]init];
_tableView.tableHeaderView = _detailsView;

I don't know if I have to set some constraints directly on the CustomView, I think the height of the CustomView is determined by the constraints on the UILabel "title" in it.

EDIT 2: After another investigation it seems the height and width of the CustomView are correctly calculated, but the top of the CustomView is still at the same level than the top of the UITableView and they move together when I scroll.

I asked and answered a similar question here. In summary, I add the header once and use it to find the required height. That height can then be applied to the header, and the header is set a second time to reflect the change.

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.header = [[SCAMessageView alloc] init];
    self.header.titleLabel.text = @"Warning";
    self.header.subtitleLabel.text = @"This is a message with enough text to span multiple lines. This text is set at runtime and might be short or long.";

    //set the tableHeaderView so that the required height can be determined
    self.tableView.tableHeaderView = self.header;
    [self.header setNeedsLayout];
    [self.header layoutIfNeeded];
    CGFloat height = [self.header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    //update the header's frame and set it again
    CGRect headerFrame = self.header.frame;
    headerFrame.size.height = height;
    self.header.frame = headerFrame;
    self.tableView.tableHeaderView = self.header;
}

If you have multi-line labels, this also relies on the custom view setting the preferredMaxLayoutWidth of each label:

- (void)layoutSubviews
{
    [super layoutSubviews];

    self.titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.titleLabel.frame);
    self.subtitleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.subtitleLabel.frame);
}

or perhaps more generally:

override func layoutSubviews() {
    super.layoutSubviews()  
    for view in subviews {
        guard let label = view as? UILabel where label.numberOfLines == 0 else { continue }
        label.preferredMaxLayoutWidth = CGRectGetWidth(label.frame)
    }
}
Update January 2015

Unfortunately this still seems necessary. Here is a swift version of the layout process:

tableView.tableHeaderView = header
header.setNeedsLayout()
header.layoutIfNeeded()
header.frame.size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
tableView.tableHeaderView = header

I've found it useful to move this into an extension on UITableView:

extension UITableView {
    //set the tableHeaderView so that the required height can be determined, update the header's frame and set it again
    func setAndLayoutTableHeaderView(header: UIView) {
        self.tableHeaderView = header
        header.setNeedsLayout()
        header.layoutIfNeeded()
        header.frame.size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
        self.tableHeaderView = header
    }
}

Usage:

let header = SCAMessageView()
header.titleLabel.text = "Warning"
header.subtitleLabel.text = "Warning message here."
tableView.setAndLayoutTableHeaderView(header)

Getting Auto Layout to Work in a UITableView, Even if you have no choice but to use UITableView, I've found it is usually possible to get it working with Auto Layout by following a few key  Text Length: If you have a longer text then your intrinsicContentSize's width will increase Line breaks: If you add then the intrinsicContentSize's width will the maximum width of all lines. Number of allowed lines: You must set the numberOfLines to 0 otherwise the you won't have multiple lines.

I've been unable to add a header view using constraints (in code). If I give my view a width and/or a height constraint, I get a crash with the message saying:

 "terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super."

When I add a view in the storyboard to my table view, it shows no constraints, and it works fine as a header view, so I think that the placement of the header view isn't done using constraints. It doesn't seem to behave like a normal view in that regard.

The width is automatically the width of the table view, the only thing you need to set is the height -- the origin values are ignored, so it doesn't matter what you put in for those. For instance, this worked fine (as does 0,0,0,80 for the rect):

UIView *headerview = [[UIView alloc] initWithFrame:CGRectMake(1000,1000, 0, 80)];
headerview.backgroundColor = [UIColor yellowColor];
self.tableView.tableHeaderView = headerview;

Auto Layout Guide: Working with Self-Sizing Table View Cells, In iOS, you can use Auto Layout to define the height of a table view cell; the table view's rowHeight property to UITableViewAutomaticDimension . Additionally, try to make the estimated row height as accurate as possible. ios,uistoryboard Is it possible to have the storyboard scale everything up or down depending on the screen size or do I have to do it programmatically? For example the UI on iPhone 6 plus would look exactly like the one on iPhone 5 but just larger.

I saw a lot of methods here doing so much unnecessary stuff, but you don't need that much to use auto layout in the header view. You just have to create you xib file, put your constraints and instantiate it like this:

func loadHeaderView () {
        guard let headerView = Bundle.main.loadNibNamed("CourseSearchHeader", owner: self, options: nil)?[0] as? UIView else {
            return
        }
        headerView.autoresizingMask = .flexibleWidth
        headerView.translatesAutoresizingMaskIntoConstraints = true
        tableView.tableHeaderView = headerView
    }

Self-sizing Table View Cells, This will simplify our view controllers and let's us re-use code where possible. For instance, if we need to move from using a tableView to a  Do i have to use programatically or using autolayout? Appreciate for the answer. Thanks.. Answer: If use AutoLayout the use this code. You try to set the UITableView properties estimatedHeight.

Another solution is to dispatch the header view creation to the next main thread call:

- (void)viewDidLoad {
    [super viewDidLoad];

    // ....

    dispatch_async(dispatch_get_main_queue(), ^{
        _profileView = [[MyView alloc] initWithNib:@"MyView.xib"];
        self.tableView.tableHeaderView = self.profileView;
    });
}

Note: It fix the bug when the loaded view has a fixed height. I haven't tried when the header height only depends on its content.

EDIT :

You can find a cleaner solution to this problem by implementing this function, and calling it in viewDidLayoutSubviews

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    [self sizeHeaderToFit];
}

Self-Sizing Cells with UITableView and Auto Layout, This snippet describes how to use auto layout constraints to resize cell views according to their content. Yes, this is possible using CloudKit. You'll need a CKContainer, and you'll ask it to fetch the user record ID. That record ID is unique for your apps, but is also stable for that user this means the same iCloud account will have the same record ID, regardless of which

You can get autolayout to provide you with a size by using the systemLayoutSizeFittingSize method.

You can then use this to create the frame for your application. This technique works whenever you need to know the size of a view that uses autolayout internally.

The code in swift looks like

//Create the view
let tableHeaderView = CustomTableHeaderView()

//Set the content
tableHeaderView.textLabel.text = @"Hello world"

//Ask auto layout for the smallest size that fits my constraints    
let size = tableHeaderView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)

//Create a frame    
tableHeaderView.frame = CGRect(origin: CGPoint.zeroPoint, size: size)

//Set the view as the header    
self.tableView.tableHeaderView = self.tableHeaderView

Or in Objective-C

//Create the view
CustomTableHeaderView *header = [[CustomTableHeaderView alloc] initWithFrame:CGRectZero];

//Set the content
header.textLabel.text = @"Hello world";

//Ask auto layout for the smallest size that fits my constraints
CGSize size = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

//Create a frame
header.frame = CGRectMake(0,0,size.width,size.height);

//Set the view as the header  
self.tableView.tableHeaderView = header

It should also be noted that in this particular instance, overriding requiresConstraintBasedLayout in your subclass, does result in a layout pass being performed, however the results of this layout pass are ignored and the system frame set to the width of the tableView and 0 height.

Using Auto Layout Constraints for the height of UITableView cells, UITableView requires auto layout to specify the height because there's intrinsic We would like to modify this behaviour to be able to do something like this… Once you have self sizing tableView, it's very convenient to use them inside  If use AutoLayout the use this code You try to set the UITableView properties estimatedHeight . -(void)viewWillAppear:(BOOL)animated{ _messageField.delegate = self; _tableView.estimatedRowHeight = 65.0; _tableView.rowHeight = UITableViewAutomaticDimension; }

Swift 4 recipe: Self sizing table view - Dushyant Bansal, By using automatic row height you can create table view cells, that First, you have to use auto layout and elements that have an intrinsic  Tout fonctionne bien sauf le UITableView affiche toujours au-dessus le CustomView, par ci-dessus je veux dire le CustomView est sous le UITableView donc il ne peut pas être vu ! il semble que peu importe ce que je fais, le height du UITableView ' tableHeaderView est toujours 0 (ainsi que la largeur, x et y).

25-UITableView#1.Auto layout UITableView and UITableViewCell in , Displaying dynamic content in TableView or CollectionView with cells of Use Auto Layout for the UI elements inside the TableView cells. staggered grid view​, we would likely need to use some other external libraries. Getting video from Asset Catalog using On Demand ressources. ios,xcode,xcode7,ios9,asset-catalog. I think its not possible to use Asset Catalog for video stuff, Its simplify management of images. Apple Documentation Use asset catalogs to simplify management of images that are used by your app as part of its user interface.

UITableView: Automatic Row Height, ios,uitableview,autolayout. If use AutoLayout the use this code You try to set the UITableView properties estimatedHeight. -(void)viewWillAppear:(BOOL)animated{ _messageField.delegate = self; _tableView.estimatedRowHeight = 65.0; _tableView.rowHeight = UITableViewAutomaticDimension; } Other wise use this UITableView Delegate Method - (CGFloat

Comments
  • Yes, it is possible. Can you show the code you're using? It's difficult to advise without knowing what constraints you have set up on the header view.
  • An easy way for you to accomplish this is to add that view in IB to the tableView..just create the view in the same scene containing the tableview and drag it to the table.
  • I'm trying to avoid IB the most I can, so far I didn't have to use it, if I can't get it to work I'll try with IB
  • Apple advises developers to use IB whenever possible when it comes to autolayout. It really helps in avoiding a lot of inconsistency problems.
  • The true complete autolayout solution is here
  • An alternative to using preferredMaxLayoutWidth is adding a width constraint (equal to the table view's width) on the header view prior to using systemLayoutSizeFittingSize:.
  • NOTE: if you experiencing that the header is above the first cells, then you forgot to reset the header property to self.tableView.tableHeaderView
  • Often it amazes me how tricky it can be to do something completely trivial like this.
  • NOTE: If you need to get exact width as tableView, you should get height with required horizontal priority let height = header.systemLayoutSizeFittingSize(CGSizeMake(CGRectGetWidth(self.bounds), 0), withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityFittingSizeLevel).height
  • Just Use header.setNeedsLayout() header.layoutIfNeeded() header.frame.size = header.systemLayoutSizeFitting(UILayoutFittingCompressedSize) self.tableHeaderView = header would work at iOS 10.2
  • I had that exception too but adding a category to UITableView fixed it I found it in that answer : stackoverflow.com/questions/12610783/…
  • I'm still gonna try what you suggest, but tomorrow morning, it's 1:34 am I'm going to bed, thank you very much for taking the time to answer ! (But I really want to not specify a height, I would like it to be calculated by the constraints I set up on the label in the CustomView)
  • I've tried it and yeah setting the frame works, but I was looking for a way to avoid setting the frame, I'll keep looking and if I find nothing else I'll accept your answer