Skip to content

No auto layout on first load tablewview #10

Open

Description

@Edig

I have a problem. I create a TableViewController with dynamic height on the cells. I follow this answer

http://stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights/18746930#18746930

My problem its that (I copy the exact constraints) when I load information, like 2-3 lines it only appear the first or second line and the other line I need to scroll until the cell its outside the screen and bring it inside again and it comes with the other line. I hop eI explain my self.

I have my code, mostly the same as that post

var cell = tableView.dequeueReusableCellWithIdentifier("CellP", forIndexPath: indexPath) as CellPTableViewCell

        if (indexPath.row+1)%2 == 0 {
            cell.contentView.backgroundColor = UIColor(red: 244/255, green: 244/255, blue: 244/255, alpha: 1.0)
        }

        cell.label1.text = "\(userName) \(userLast)"
        cell.label1.text = userText

        cell.setNeedsUpdateConstraints()
        cell.updateConstraintsIfNeeded()
        return cell

Any ideas? the constraints are exactly the same as the post, I just modify the font (I try with the font he propose and its the same error)

Edit: I try it on iPhone 6 (Physically). and iPhone 4S (Simulator)

Best,

Activity

  1. smileyborg commented on Oct 10, 2014

    @smileyborg
    Owner

    Hi @Edig,

    I don't think I have enough information to try and help. Did you compare your code to the code of this sample project on GitHub?

    You'll probably need to share your entire project (or a sample project that illustrates the issues your seeing) if you would like more help in debugging.

    90% of the issues people have with this is that their constraints are not correct, even though they think they are. I recommend double and triple checking that you have all the constraints you need -- it sounds like you could have an ambiguous layout issue.

  2. Edig commented on Oct 10, 2014

    @Edig
    Author

    Hi @smileyborg , any email? also I copy the cell you have, exactly the same. And the cells resize perfectly but I need to reload the cell (put it off screen and put it again on screen)

    The only thing I dones't have its

    self.tableView.registerNib ()

    because I have prototype cells

  3. Edig commented on Oct 10, 2014

    @Edig
    Author

    Hi @smileyborg I really don't know why but If I add this

    override func viewDidAppear(animated: Bool) {
        self.tableView.reloadData()
    }
    

    Works perfectly, it seems that in the first render of the cells, the system can't determine the exact height of the constraints.

  4. smileyborg commented on Oct 10, 2014

    @smileyborg
    Owner

    You can email tfox [at] smileyborg (dot) com. The issue could be related to the preferredMaxLayoutWidth of multi-line labels - not being set the first layout pass.

  5. Edig commented on Oct 10, 2014

    @Edig
    Author

    Hi @smileyborg
    cell.label2.preferredMaxLayoutWidth = CGRectGetWidth(cell.label2.frame)

    work with the new cells, only I have a problem with the first 10 cells that appears without scrolling

  6. smileyborg commented on Oct 10, 2014

    @smileyborg
    Owner

    You'll have to share your project to help debug further. Which version of iOS are you testing on?

  7. smileyborg commented on Oct 10, 2014

    @smileyborg
    Owner

    This may be the same issue as #7. Can you try adding this code to your UITableViewCell subclass:

    override func layoutSubviews() {
        super.layoutSubviews()
    
        placeName.preferredMaxLayoutWidth = CGRectGetWidth(placeName.frame)
    
        super.layoutSubviews()
    }
    

    If that doesn't work, try the following in your cellForRowAtIndexPath method:

    cell.placeName.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds)
    

    Basically, it seems like there is a bug with the Interface Builder "Automatic" preferredMaxLayoutWidth here.

  8. Edig commented on Oct 10, 2014

    @Edig
    Author

    @smileyborg. With that modification it renders the height fine, but the distance between the label1 and label 2 (like your example) differ. When I hide and show the cell it appear with the exact position. Also the height of the cell changes

    I try with

    cell.placeName.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds)

    The one its >=0 ( I change to = 0, and the same)

  9. smileyborg commented on Oct 10, 2014

    @smileyborg
    Owner

    Interesting, I'm not sure exactly what's going on. But it seems to suggest there are bugs with Apple's implementation of self sizing cells particularly when loading from a Storyboard/nib. You may wish to switch to implementing it in code (as in this example project), as it seems to be more reliable.

  10. Edig commented on Oct 10, 2014

    @Edig
    Author

    @smileyborg Ok thanks! I will try it! and I let you know how it goes

  11. PetahChristian commented on Nov 16, 2014

    @PetahChristian

    The problem with cells being loaded from a storyboard is that the cell's width does not initially correspond to the tableView's width (which affects the label's preferredMaxLayoutWidth). Reloading simply reuses a cell which at that point has the proper frame size.

    Cells instantiated in code are created with the right dimensions from the start, so they appear correct at the first load.

  12. Edig commented on Nov 16, 2014

    @Edig
    Author

    Hi peter,

    I had the same problem and I solve it by putting any-any in the class size instead of compact-any

    And now works great

    Enviado desde mi iPhone

    El nov 16, 2014, a las 1:12 PM, Peter Jensen notifications@github.com escribió:

    The problem with cells being loaded from a storyboard is that the cell's width does not initially correspond to the tableView's width (which affects the label's preferredMaxLayoutWidth). Reloading simply reuses a cell which at that point has the proper frame size.

    Cells instantiated in code are created with the right dimensions from the start, so they appear correct at the first load.

    —
    Reply to this email directly or view it on GitHub.

  13. smileyborg commented on Nov 16, 2014

    @smileyborg
    Owner

    @PetahChristian You're probably right. But if so, this is definitely a bug on Apple's side. If you can confirm your hypothesis and still see issues with the latest iOS version I would definitely file a radar.

  14. smileyborg commented on Jan 13, 2015

    @smileyborg
    Owner

    By the way, not sure if anyone here had made progress on this issue. But I ran into something (potentially) similar recently, and found a workaround that may be helpful...see my comment at the bottom of this article:

    If you're having row height issues on iOS 8.0 or 8.1, where your cells are sized incorrectly, after you initially call [tableView reloadData] to populate the table with cells, add the following:

    [tableView setNeedsLayout];
    [tableView layoutIfNeeded];
    [tableView reloadData];

    Forcing a layout pass on the table view and then doing a 2nd reloadData caused the cells to be sized correctly in my case (some debugging clearly indicated that the issue was with the table view's internal height calculation, not with the cell). This workaround also is invisible to the user, since it all happens synchronously before a redraw.

  15. smileyborg commented on Apr 5, 2015

    @smileyborg
    Owner

    Here's another workaround that may solve this issue: #22 (comment)

  16. 8of commented on May 7, 2015

    @8of

    @smileyborg The comment before last one helped me a lot - thanks! 🆒

  17. RishabhTayal commented on May 15, 2015

    @RishabhTayal

    Wrote a nice little extension to fix this issues based in @smileyborg 's answer.

    extension UITableView {
        func reloadDataWithAutoSizingCellWorkAround() {
            self.reloadData()
            self.setNeedsLayout()
            self.layoutIfNeeded()
            self.reloadData()
        }
    }
    

    Just call self.tableView.reloadDataWithAutoSizingCellWorkAround() instead of self.tableView.reloadData()

  18. smileyborg commented on May 16, 2015

    @smileyborg
    Owner

    @RishabhTayal That's nifty, but I would caution against using this all the time instead of reloadData -- you should only need the workaround on first load of the table view.

    Doing these extra reloads and layout passes for additional calls to reload the table view will just be wasted CPU processing. So I would recommend only doing it when necessary (the first time) and just using reloadData from then on.

  19. RishabhTayal commented on May 16, 2015

    @RishabhTayal

    @smileyborg Yeah of-course. That extension is meant only for the first load.

  20. nordringrayhide commented on Jun 6, 2015

    @nordringrayhide

    @RishabhTayal +1: you've just saved my mind, yeah it works for me, thanks :-)

  21. JimVanG commented on Jun 29, 2015

    @JimVanG

    Alright, so I can get my UITableViewCells that are ON screen to initially load in the correct height. But I can't get my UITableViewCells that are off screen to load in the proper height. I have to scroll to them, then scroll up-and-down, to force them to become the proper height.

    I'm doing this after my initial call to self.reloadData():

    self.reloadData()
    self.setNeedsLayout()
    self.layoutIfNeeded()
    self.reloadData()
    

    I have this in my cell subclass:

    override func layoutSubviews() {
        super.layoutSubviews()
    
        placeName.preferredMaxLayoutWidth = CGRectGetWidth(placeName.frame)
    
        super.layoutSubviews()
    }
    

    and this in my cellForRowAtIndexPath:
    cell.placeName.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds)

    I'm also using the estimatedRowHeight, and overriding override public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath), to return the calculated cell height based upon the height of my UILabel in the cell.

    Anyone have any information on getting the off-screen cells to initially load in the correct cell height?

    thank you!

  22. JimVanG commented on Jun 30, 2015

    @JimVanG

    So in order to get the dynamic cell heights to work properly I had to completely configure my cell inside of tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath), to the point where it pretty much looked like my cell configuration in cellForRowAtIndexPath, this is pretty annoying but it works. I'm not sure why I have to configure the entire cell just to get the correct height instead of just returning a number.

    For a good example of how to set up your cell in tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) check out this link, http://www.raywenderlich.com/73602/dynamic-table-view-cell-height-auto-layout , specifically the part on tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath).

  23. gtsifrikas commented on Nov 24, 2016

    @gtsifrikas

    If you do this:

    tableView.reloadData()
    UIView.setAnimationsEnabled(false)
    tableView.beginUpdates()
    tableView.endUpdates()
    UIView.setAnimationsEnabled(true)

    The first visible cells will get the correct height

  24. grangej commented on Dec 5, 2016

    @grangej

    @gtsifrikas you sir, are a genius :-)

  25. thiagorossener commented on Mar 20, 2017

    @thiagorossener

    @gtsifrikas I could not make this work :(

    Here is my code:

    private func addCampaign(campaign: Campaign) {
            let rowToInsert = self.campaignsList.insert(campaign)
            self.campaignsMap[campaign.key] = rowToInsert
            UIView.setAnimationsEnabled(false)
            self.tableView.beginUpdates()
            self.tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: rowToInsert + 1, inSection: 0)], withRowAnimation: .Top)
            self.tableView.endUpdates()
            UIView.setAnimationsEnabled(true)
        }
    

    My problem is exactly the same problem of that guy:
    https://forums.developer.apple.com/thread/67560

    Which I believe is the same problem everyone here is facing. So, I turned off the animation and turned on again, as you said, but that didn't work.

    This issue looks like a common issue, but until now I couldn't find any good answer for that.

  26. goneale commented on Nov 26, 2018

    @goneale

    Confirmed @gtsifrikas that hack works. Quicker I can move to React the better.... Crazy we have to do all this leg work for ios when it comes to dynamic data and images.

  27. handlermyanmar commented on Jun 12, 2019

    @handlermyanmar

    2019 and Xcode still facing this problem. Thanks for the solution guys.

  28. awilliams88 commented on Aug 9, 2019

    @awilliams88

    This may be the same issue as #7. Can you try adding this code to your UITableViewCell subclass:

    override func layoutSubviews() {
        super.layoutSubviews()
    
        placeName.preferredMaxLayoutWidth = CGRectGetWidth(placeName.frame)
    
        super.layoutSubviews()
    }
    

    If that doesn't work, try the following in your cellForRowAtIndexPath method:

    cell.placeName.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds)
    

    Basically, it seems like there is a bug with the Interface Builder "Automatic" preferredMaxLayoutWidth here.

    @smileyborg U Rock Bro 🤘 - The auto layout bug for multi-line label took so much of my time in debugging 😔 - Thanks for your solution 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions