24

I am using iOS 8 self-sizing cells (tableView.rowHeight = UITableViewAutomaticDimension and tableView:estimatedHeightForRowAtIndexPath:) combination. It works great until I start typing something inside a cell. When I'm typing, I'm calling beginUpdates/endUpdates pair to resize my cell (text view grows as I type and shrinks as I delete) but each call results in a bad jump to top of the table view. If I remove the beginUpdates/endUpdates pair then it doesn't jump but my cell doesn't resize as I type.

Here is a demonstration of the issue:

enter image description here

How can I get my cell to resize correctly as I type while not jumping to the top of the table view? I am only targeting iOS >= 8 so I don't need any kind of iOS 7 compatibility.

Can Poyrazoğlu
  • 33,241
  • 48
  • 191
  • 389
  • 1
    Have this exact issue. Your gif is a perfect demonstration. Eagerly awaiting an answer here. :) – Joshua Dance Mar 10 '15 at 04:52
  • I filed a Radar on this, as it could be a bug - http://openradar.appspot.com/radar?id=6381017677955072 – Joshua Dance Mar 10 '15 at 16:42
  • Also this question seems to be same issue and has some answers that are claimed to fix it - http://stackoverflow.com/questions/27460698/uitableview-flickers-stutters-while-entering-text-in-auto-resizing-textview – Joshua Dance Mar 10 '15 at 16:43
  • I have the exact same issue. Really hoping for an answer here, too... – David Silverfarmer Mar 16 '15 at 13:38
  • You don't need to refresh the whole tableview just reload the relative cell. And you can post the code here. – SeanChense May 10 '16 at 12:02
  • Did you ever come up wit a real solution for this problem? typing and resizing in a UITableViewCell is really a lot of pain... :( – Georg Jul 14 '16 at 13:17
  • @Georg I've never got away with that using auto-sizing cells. the only "solution" (which is a workaround, not a real solution) seems to be returning to pre-iOS 8-esque manual cell size calculation and returning that size in delegate method. At least, it is what I did. – Can Poyrazoğlu Jul 14 '16 at 21:00
  • @CanPoyrazoğlu look at the below answer, this will help you. I also happened to face this issue – Manoj Aug 01 '16 at 06:53

5 Answers5

18

I was implementing the exactly the same thing for chat app and getting the same issue as you are getting now. This thing helped me out. Let me know if this works for you too.

UIView.setAnimationsEnabled(false)
tableView.beginUpdates()
cell.textView.scrollRangeToVisible(NSMakeRange(cell.textView.text.characters.count-1, 0))
tableView.endUpdates()
UIView.setAnimationsEnabled(true)
tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: false)
Manoj
  • 1,019
  • 9
  • 17
2

I found solution from Manoj Aher to work fine - text doesn't jump at all. But in my case I had to extend for situations when user might type much more text (so that the table cell is bigger than the visible part of the table) and then returns to edit this text somewhere at the beginning or in the middle. So I had to scroll the table cell to Top or Middle depending on where the user is typing to keep the typing position visible.

First, remember the indexPath for the cell in any convenient way. For example:

var cellIndexChosenForEdition: NSIndexPath
...

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
     cellIndexChosenForEdition = indexPath
     ...
}

In shouldChangeTextInRange or any other method which is called when user types (shown here method will be called when your view controller conforms to UITextViewDelegate protocol):

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    ...

    UIView.setAnimationsEnabled(false)
    MyTableView.beginUpdates()
    MyTableView.endUpdates()
    UIView.setAnimationsEnabled(true)

    if let textStartPosition: UITextPosition = textView.selectedTextRange?.start {
        let cursorPosition = textView.offsetFromPosition(textView.beginningOfDocument, toPosition: textStartPosition)

        if textView.text.characters.count - cursorPosition < 170 {
            table_create_issue.scrollToRowAtIndexPath(cellIndexChosenForEdition, atScrollPosition: .Bottom, animated: false)
        } else if cursorPosition > 200 {
            table_create_issue.scrollToRowAtIndexPath(cellIndexChosenForEdition, atScrollPosition: .Middle, animated: false)
        } else {
            table_create_issue.scrollToRowAtIndexPath(cellIndexChosenForEdition, atScrollPosition: .Top, animated: false)
        }
    }
    ...
}

*constants 200 and 170 should be changed to fit your concrete situation

**I didn't use scrollRangeToVisible because my textView height is always equal to cell height and never scrolls.

Community
  • 1
  • 1
Vitalii
  • 4,267
  • 1
  • 40
  • 45
1

I'm having the same problem, and have been able to minimize (but not eliminate) the jumping by only doing the resize/update notification when the intrinsic size of the content has actually changed, e.g.:

Swift

var textViewHeight: CGFloat = 0.0  // Set in viewWillAppear as below
...
func textViewDidChange(textView: UITextView) {
    let newHeight = textView.intrinsicContentSize().height
    if textViewHeight != newHeight{
        textViewHeight = newHeight
        tableView.beginUpdates()
        tableView.endUpdates()
    }
}

Objective-C

 CGFloat textViewHeight = 0.0;  // Set in viewWillAppear as below
 ...
 (void)textViewDidChange:(UITextView *)textView {
    CGFloat newHeight = [textView intrinsicContentSize].height;
    if (textViewHeight != newHeight){
        textViewHeight = newHeight
        [tableView beginUpdates];
        [tableView endUpdates];
    }
}
JustinHK
  • 758
  • 1
  • 6
  • 19
0

Are your reseting frame of Table View Cell on text begin editing? If yes, then you can check your variables sometimes due to memory allocation variables deallocate. Use break points and check variable values that can not be change according your requirement.

Shuan
  • 53
  • 7
-1

Auto layout have some drawback associated with it. When you start typing it jump because all other cell are adjusting their size so it will be better if you calculate the dimensions of cell on runtime only.