outerstorm
outerstorm

Reputation: 742

UITableView Section Header Automatic Height Not Updated Properly

I am running into an issue with automatic/dynamic UITableView section header views that contain a UILabel that wraps (numberOfLines = 0). The height is not being calculated properly, especially once you scroll the table and the views are reused. Sometimes the UILabel wraps, sometimes it is truncated, sometimes one or more of the labels are not visible, and sometimes there is extra spacing between the labels. The custom view contains a vertical UIStackView with three UILabels, once of which wraps.

A complete sample app demonstrating the issue can be found at https://github.com/outerstorm/tableviewHeaderTest.

The section header heights are set to automatic in viewDidLoad with the following:

    tableView.sectionHeaderHeight = UITableViewAutomaticDimension
    tableView.estimatedSectionHeaderHeight = 30.0

and also have implemented the following heightForHeaderInSection just to try to get it to work:

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return UITableViewAutomaticDimension
}

I have also tried calling setNeedsLayout() and layoutIfNeeded() at various points to no avail. Any suggestions would be greatly appreciated.

Below is a screenshot of the behavior seen in the app. The first section is cutoff and the second section is too tall:

enter image description here

Upvotes: 15

Views: 10580

Answers (6)

krishna solanki
krishna solanki

Reputation: 53

Add

self.label1.preferredMaxLayoutWidth = self.label1.frame.size.width
self.label1.numberoflines = 0;
self.label1.linebreakmode = NSLineBreakByWordWrapping;

in awakeFromNib method or Kindly check this once

Upvotes: 0

Alex Chase
Alex Chase

Reputation: 1091

From the code's documentation:

// tableView:titleForHeaderInSection: or tableView:titleForFooterInSection: if the title is not nil.

In other words. UITableViewAutomaticDimension is only intended for use if you are providing a section title using titleForHeaderInSection or titleForFooterInSection

Upvotes: 1

Anuj Panwar
Anuj Panwar

Reputation: 683

A workaround can be hold the header views in array and then return the height of view from estimated height method

for _ in 0 ..< data.count {

        let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: "CustomHeaderView") as! CustomHeaderView
        view.setup()
        headerViews.append(view)
    }


func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat
{
    let view = headerViews[section] as? UIView
    return (view?.frame.size.height)!
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    return headerViews[section] as? UIView
}

Upvotes: 1

Jaffer Sheriff
Jaffer Sheriff

Reputation: 1564

Just add estimatedHeightForHeaderInSection function and return your estimated height. It will resolve your issue. Download your modified project from here

func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat 
{
    return 30;
}

Upvotes: 3

PGDev
PGDev

Reputation: 24341

I have faced this kind of issue recently.

I solved it by setting preferredMaxLayoutWidth of multiline labels, i.e.

Before setting the value in labels, set their preferredMaxLayoutWidth as:

self.label1.preferredMaxLayoutWidth = self.label1.frame.size.width
self.label2.preferredMaxLayoutWidth = self.label2.frame.size.width
self.label3.preferredMaxLayoutWidth = self.label3.frame.size.width

Upvotes: 3

weikel
weikel

Reputation: 164

In general

heightForHeaderInSection

always called before

viewForHeaderInSection

when using UITableViewAutomaticDimension, sectionheader height will only calculate once unless called tableview.reloadData() manually.

In the code, you change sectionheader text everytime. the height was calculate at the first time, and doesnt change automatic.

you can change setup func to:

func setup(someNum: Int) {

    let text = String(repeating: "This is where the really long text goes so that it will wrap lines appropriately", count: someNum)

    mainLabel.text = text
}

and pass the section index to the function

Upvotes: 1

Related Questions