3

Summary

Resizing and reloading rows in a tableView where every cell has a dynamic height calculated by constraints causes a lot of other cells to recalculate unnecessarily. How should I solve this?

An example project can be found here.

Long version

I have a view that shows the details of a company and a variable amount of cells (or cards) with more detailed information. I implemented this in a UITableViewController with dynamically sized cells, using auto layout constraints (mostly helped along by this Ray Wenderlich tutorial).

The view has the following cells with variable heights:

  • Section 0
    • Row 0: Header image
    • Row 1: Company information
    • Row 2: Buttons
  • Section X > 0
    • Row 0: About Card

The 'About Card' may or may not have a header image and can be expanded to show the entire text.

Currently I'm having four problems with this:

  1. The UITableViewController is pushed with animating: true. However, the tableView starts out behind the navigation bar and jumps down when it's finished animating. No clue why.

Update This doesn't appear to happen consistently. Joy.

TableView jumps down after push animation

  1. When doing an action that should reload the buttons to indicate the state change, it reloads the button cell nicely. However, it also causes the company info cell to jump down and animate upwards.

Updating the cell happens with the following code:

func organizationRequestsUpdated() {
    self.tableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: UITableViewRowAnimation.None)
}

Reloading a cell causes other cell to animate

  1. Tapping an About Card should expand it. I'm currently achieving this by setting label.numberOfLines = 5 at the cell initiation and using this for toggling the expand cards:

    @IBAction func tapped(sender: UITapGestureRecognizer)
    {
        if let view = sender.view?.superview as? OrganizationDetailAboutCardCell {
            tableView.beginUpdates()
            view.toggleReadMore()
            tableView.endUpdates()
        }
    }
    func toggleReadMore() {
        let expanded = aboutTextLabel.numberOfLines == 5
        aboutTextLabel.numberOfLines = expanded ? 5 : 0
    }
    

Changing variables that should trigger height change cause everything to jump around

I'm pretty sure all of these problems have to do with the automatic sizing of the cells with the constraints. However, I'm currently at a loss on how to fix it. Has anyone done automatic sizing of cells with constraints and updated the cell heights without all the tableView doing weird jumps?

  1. Popping back to the UITableViewController has most of the cells at the wrong heights. No clue why.

enter image description here

Things I've tried

Problem 2

For problem number 2, I've already tried updating reloading only the button cell;

self.tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: 2, inSection: 0)], withRowAnimation: UITableViewRowAnimation.None)

However, this counterintuitively caused all the cells in the section to recalculate incorrectly, ending up with a heap of too small cells. I've also tried this UITableViewRowAnimation.Fade however, this had the same result.

SpacyRicochet
  • 2,269
  • 2
  • 24
  • 39
  • There seems to be a **bug** for when you use `UITableViewAutomaticDimension `. See [this answer](https://stackoverflow.com/questions/8640409/how-to-keep-uitableview-contentoffset-after-calling-reloaddata/31324129#31324129) and other answers to the question. – mfaani Oct 10 '18 at 03:54

1 Answers1

2

Have you specified an estimated row height? I found this to be the source of many of my layout issues when I did this.

Another possible problem is that you need to assign fonts to labels to make them layout properly. So in your cellForRowAtIndexPath methods, specify the font that should be used on all labels/textfields/textviews.

Here is an example project here: https://github.com/sgoodwin/SelfSizingCells.

Good luck!

Samuel Goodwin
  • 1,698
  • 13
  • 17
  • Thanks! Worked like a charm. BTW, did you mean to re-specify the label fonts, even though they might already have been set in Interface Builder? – SpacyRicochet Apr 06 '15 at 09:08
  • Yes, partly because the demo app uses the system's dynamic font sizing, so they need to be re-assigned. UIFont instances are immutable, so when the dynamic font preferences are changed, you need to re-assign the fonts to display this change. – Samuel Goodwin Apr 06 '15 at 10:07
  • That just might be the answer to the first UILabel truncating at the beginning, even though it resizes appropriately. – SpacyRicochet Apr 06 '15 at 10:32