Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resize UITableViewCell containing UITextView upon typing

Tags:

I have an UITableViewController that contains a custom cell. Each cell was created using a nib and contains a single non-scrollable UITextView. I have added constraints inside each cell so that the cell adapts its height to the content of the UITextView. So initially my controller looks like this :

initial state

Now I want that when the user types something in a cell its content automatically adapts. This question has been asked many times, see in particular this or the second answer here. I have thus written the following delegate in my code :

- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {     [self.tableView beginUpdates];     [self.tableView endUpdates];     return YES; } 

However it leads to the following strange behavior : all constraints are ignored and all cells height collapse to the minimal value. See the picture below:

wrong behavior

If I scroll down and up the tableView in order to force for a new call of cellForRowAtIndexPath, I recover the correct heights for the cells:

correct behavior

Note that I did not implement heightForRowAtIndexPath as I expect autoLayout to take care of this.

Could someone tell me what I did wrong or help me out here ? Thank you very much !

like image 946
vib Avatar asked Jul 23 '15 18:07

vib


2 Answers

Here is a swift solution that is working fine for me. Provided you are using auto layout, you need assign a value to estimatedRowHeight and then return UITableViewAutomaticDimension for the row height. Finally do something similar to below in the text view delegate.

override func viewDidLoad() {     super.viewDidLoad()     self.tableView.estimatedRowHeight = 44.0 }  override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {     return UITableViewAutomaticDimension }  // MARK: UITextViewDelegate func textViewDidChange(textView: UITextView) {      // Calculate if the text view will change height, then only force      // the table to update if it does.  Also disable animations to     // prevent "jankiness".      let startHeight = textView.frame.size.height     let calcHeight = textView.sizeThatFits(textView.frame.size).height  //iOS 8+ only      if startHeight != calcHeight {          UIView.setAnimationsEnabled(false) // Disable animations         self.tableView.beginUpdates()         self.tableView.endUpdates()          // Might need to insert additional stuff here if scrolls         // table in an unexpected way.  This scrolls to the bottom         // of the table. (Though you might need something more         // complicated if editing in the middle.)          let scrollTo = self.tableView.contentSize.height - self.tableView.frame.size.height         self.tableView.setContentOffset(CGPoint(x: 0, y: scrollTo), animated: false)          UIView.setAnimationsEnabled(true)  // Re-enable animations. } 
like image 121
atlwx Avatar answered Sep 17 '22 15:09

atlwx


My solution is similar to @atlwx but a bit shorter. Tested with static table. UIView.setAnimationsEnabled(false) is needed to prevent cell's contents "jumping" while table updates that cell's height

override func viewDidLoad() {     super.viewDidLoad()     self.tableView.estimatedRowHeight = 44.0 }  override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {     return UITableViewAutomaticDimension }  func textViewDidChange(_ textView: UITextView) {     UIView.setAnimationsEnabled(false)     textView.sizeToFit()     self.tableView.beginUpdates()     self.tableView.endUpdates()     UIView.setAnimationsEnabled(true) } 
like image 39
Yaiba Avatar answered Sep 18 '22 15:09

Yaiba