John Doe
John Doe

Reputation: 1609

UITableViewAutomaticDimension Causing Problems

I'm making an app with text posts, but I realize that a lot of the text posts will be really long so I added a show all and less button, but when you press it sometimes the cell disappears and you scroll up and it skips to the middle of the cell. Here is what it looks like since it's hard to explain...

http://makeagif.com/kMFG-g

I believe this happens due to something with this...

table.rowHeight = UITableViewAutomaticDimension

but it's necessary to make the cells to display custom amounts of text. But anyway here is the code.

Here is the actual function that makes it happen...

var showingMore = [Bool]()

func showAllAndLess(sender: AnyObject) {

    var buttonPosition: CGPoint = sender.convertPoint(CGPointZero, toView: self.table)

    var indexPath: NSIndexPath = self.table.indexPathForRowAtPoint(buttonPosition)!

    if showingMore[indexPath.row] {
        sender.setTitle("Show Less", forState: .Normal)
    } else {
        sender.setTitle("Show All", forState: .Normal)
    }

    showingMore[indexPath.row] = !showingMore[indexPath.row]

    table.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
}

Here is the code in the cellForRowAtIndexPath method...

showingMore.append(false)

        postCellObj.showAllAndLessButton.hidden = true

        if showingMore[indexPath.row] {
            postCellObj.message.text = messageString
            postCellObj.showAllAndLessButton.setTitle("Show Less", forState: .Normal)
            postCellObj.showAllAndLessButton.hidden = false
            println("Showing Less")
        }

        else if count(messageString) >= 800 {
            var messageNs = messageString as NSString
            var messageFinal = messageNs.substringWithRange(NSRange(location: 0, length: 800))
            postCellObj.message.text = messageFinal as String + "..."
            postCellObj.showAllAndLessButton.setTitle("Show All", forState: .Normal)
            postCellObj.showAllAndLessButton.hidden = false

        } else {
            postCellObj.message.text = messageString

        }

    }

Thanks for reading! I hope I gave enough information. And if you need more just say something. (:

P.S. the variable "messageString" is the message text.

Upvotes: 0

Views: 415

Answers (1)

Andrii Chernenko
Andrii Chernenko

Reputation: 10204

This is a known issue. UITableView dumps previously calculated cell heights if you modify data source (add or remove rows). This is no problem when you scroll down, but as soon as you start scrolling up table view starts jumping.

The solution is to cache cell heights yourself. More information here: https://github.com/smileyborg/TableViewCellWithAutoLayoutiOS8/issues/17

Sometimes jumpy scrolling can be caused by incorrect estimation of cell height (if it is off by an order of magnitude). In this case you can adjust your estimate according to the amount of text (no need to be very precise, though).

Here's a way to estimate the text height:

class func estimatedHeightForText(text: String, andWidth width: CGFloat) ->  CGFloat {
    let paragraphCount = (text.characters.split { $0 == "\n" }.map { String($0) }).count + 1

    // 7 is approximate width of character in points
    let charsPerLine = width / 7
    let lineCount = text.characters.count / Int(round(charsPerLine)) + 1

    // 14 is approximate height of line
    let estimatedHeight = 14 * CGFloat(max(lineCount, paragraphCount))

    return estimatedHeight
}

Upvotes: 1

Related Questions