Calibration table height update with text view scale

I have a tabular view similar to the Compose screen in Mail, where one of the cells is used to enter text. I would like the cell to automatically change, limiting the contentViewcells to its subtext UITextViewusing an automatic layout. In the table view, rowHeightand estimatedRowHeightset to UITableViewAutomaticDimension. In addition, the scrollEnabledvalue for the text view property is set false, so that it reports it intrinsicContentSize.

However, the cell does not update its height, as lines of text are entered by the user, although the text view itself updates its own content size. As far as I know, the only way to request this manually is to invoke the table view beginUpdates()and endUpdates(). Then the cell height is updated correctly, but it also causes a re-layout of the entire table view. Here's a (alien) sample code demonstrating the problem .

How can I reflect changes in the form of cell text without laying out the entire view of the table?

+4
source share
3 answers

UITableViewCell. UITableView, , .

(cellForRowAtIndexPath) . tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)

reloadRowsAtIndexPaths reloadData(). , tableView.beginUpdates tableView.endUpdates, , .Fade.

. reloadRowsAtIndexPaths(_:withRowAnimation:) documentation.


, .

Animated demo

+1

reloadRowsAtIndexPaths , UITextField resignFirstResponder, , , : .. .

, beginUpdates() endUpdates() , , scrollEnabled UITextView, textViewDidChange.

textViewDidChange, , .

UITableViewCell:

class TableViewTextViewCell : UITableViewCell, UITextViewDelegate {
    var refreshCell:(() -> Void)? = nil
    var textViewDirtyCount = 0

    // MARK: - UITextViewDelegate
    func textViewDidChange(_ textView: UITextView) {
        textViewDirtyCount += 1
        perform(#selector(TableViewTextViewCell.queuedTextVewDidChange),
                with: nil,
                afterDelay: 0.3) // Wait until typing stopped
    }

    func textViewDidBeginEditing(_ textView: UITextView) {
        textViewDirtyCount = 0 // initialize queuedTextVewDidChange
    }

    func textViewDidEndEditing(_ textView: UITextView) {
        textViewDirtyCount = -1 // prevent any further queuedTextVewDidChange
    }

    func queuedTextVewDidChange() {
        if textViewDirtyCount > 0 {
            textViewDirtyCount -= 1
            if 0 == textViewDirtyCount, let refreshCell = refreshCell {
                refreshCell()
            }
        }
    }
}

:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier(
        "cell", forIndexPath: indexPath) as! TableViewTextViewCell

    cell.refreshCell = {
        () -> Void in
        tableView.beginUpdates()
        tableView.endUpdates()
    }
    return cell
}

0,3 ; 0,3 , . .

Frame delay


GitHub .

+1

beginUpdates , UIView .

//inside of cellForRowAtIndexPath
cell.performCellUpdates = { [unowned self] in
    UIView.setAnimationsEnabled(false)   //the secret sauce, prevents the jitter
    self.tv.beginUpdates()
    self.tv.endUpdates()
    UIView.setAnimationsEnabled(true)    //don't forget to turn animations back on
}

...

//inside of cell subclass
func textViewDidChange(_ textView: UITextView) {
    textView.sizeToFit()
    performCellUpdates()
}

, , :)

+1

Source: https://habr.com/ru/post/1627694/


All Articles