The dynamic height of UITextView inside UITableViewCell Swift

We are going to create a project with is having UITableViewCell with a dynamic height of the row based on UITextView text length.
– Create a new project
– Drag and drop a UITableView in your UIViewController class nib file
– Create an IBOutlet of UITableView
@IBOutlet weak var tableView: UITableView!

Adding UITableViewCell class

Now create a new UITableViewCell class

Set Identifier to Cell

Now select xib file of your GrowingCell and do the following changes in order to set identifier to the cell

1. Select GrowingCell.xib
2. Select GrowingCell
3. Click on attribute inspector
4. add GrowingCell as an identifier

Add UITextView in Cell

Now next step is to add a UITextView in Cell and perform below changes

1. Select UITextView
2. Remove checkbox the properties inside of rectangle as shown in the image

Registering GrowingCell Nib

In your UIViewController class in viewDidLoad function add below code
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    let nib = UINib(nibName: "GrowingCell", bundle: nil)
    self.tableView.register(nib, forCellReuseIdentifier: "GrowingCell")
    self.tableView.tableFooterView = UIView()
    self.tableView.dataSource = self
}

Adding DataSource of UITableView

Create an extension of your UIViewController class and implement UITableViewDataSource protocol
Add below code in your UIViewController class
extension ViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "GrowingCell", for: indexPath) as!
GrowingCell
        cell.cellDelegate = self
        return cell
    }
    
}
Above code will give an error on “cell.cellDelegate = self” line but don’t worry we will fix this later.

Creating a protocol and implementing UITextViewDelegate in GrowingCell

Move to GrowingCell class
Create an outlet of UITextview
@IBOutlet weak var textView: UITextView!
Add GrowingCell protocol in this class
protocol GrowingCellProtocol: class {
    func updateHeightOfRow(_ cell: GrowingCell, _ textView: UITextView)
}
Create a weak variable of above protocol in GrowingCell class
weak var cellDelegate: GrowingCellProtocol?
Assign delegate to textView in awakeFromNib functions
override func awakeFromNib() {
    super.awakeFromNib()
    textView.delegate = self
}
Now implement UITextViewDelegate by adding below code
extension GrowingCell: UITextViewDelegate {
    
    func textViewDidChange(_ textView: UITextView) {
        if let deletate = cellDelegate {
            deletate.updateHeightOfRow(self, textView)
        }
    }
}
Finally your GrowingCell class will look as below
import UIKit
protocol GrowingCellProtocol: class {
    func updateHeightOfRow(_ cell: GrowingCell, _ textView: UITextView)
}
class GrowingCell: UITableViewCell {
    
    weak var cellDelegate: GrowingCellProtocol?
    @IBOutlet weak var textView: UITextView!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        textView.delegate = self
    }
    
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }
}
extension GrowingCell: UITextViewDelegate {
    
    func textViewDidChange(_ textView: UITextView) {
        if let deletate = cellDelegate {
            deletate.updateHeightOfRow(self, textView)
        }
    }
}

Implementing GrowingCellProtocol in UIViewController class

Now create one more extension of UIViewController class and integrate GrowingCellProtocol
extension ViewController: GrowingCellProtocol {
    
    func updateHeightOfRow(_ cell: GrowingCell, _ textView: UITextView) {
        let size = textView.bounds.size
        let newSize = tableView.sizeThatFits(CGSize(width: size.width,
                                                        height: CGFloat.greatestFiniteMagnitude))
        if size.height != newSize.height {
            UIView.setAnimationsEnabled(false)
            tableView?.beginUpdates()
            tableView?.endUpdates()
            UIView.setAnimationsEnabled(true)
            if let thisIndexPath = tableView.indexPath(for: cell) {
                tableView.scrollToRow(at: thisIndexPath, at: .bottom, animated: false)
            }
        }
    }
}
Now all set up and run the code

You can also download the source code from Github
Read our next article: Everything about CAGradientLayer in just 5 mins

4 comments on “The dynamic height of UITextView inside UITableViewCell Swift

  1. Kazi Abdullah Al Mamun

    Can you please describe ‘updateHeightOfRow’ functions lines. I can see that Row height is become dynamic only for this two line “tableView?.beginUpdates()
    tableView?.endUpdates()”
    No other lies are required.

    Reply
    1. swiftdevcenter_admin Post author

      You are right about the other lines, those are only needed when your UITextView height become big and you want to keep that cell visible at the bottom (stick with the keyboard, make sure you have the bottom constraint of table view to the height of keyboard)

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *