Search code examples
iosswiftuitableviewuitextviewuitextviewdelegate

How to embed UITextView inside UITableViewCell with custom cell that's the delegate?


I've got a UITableViewController with two custom cells - one contains a UITextField (for the user to input a title) and the other contains a UITextView (for the user to input a description). Whenever these change, I want to update my memory object (which is a struct with two variables - memoryTitle and memoryDescription).

The memoryTitle seems simple enough - on my ViewController I have the following:

 @IBAction func memoryTitleChanged(_ sender: UITextField) {
        memory.memoryTitle = sender.text ?? ""
    }

The UITextView has confused me slightly though. There's two issues I'm having - I can't create an action in the same way I can for the UITextField, so my next thought was to make the ViewController the delegate and use textViewDidChange to update memory.memoryDescription but that brings me to my second problem.

In order to make the UITextView cell resize dynamically, I used the following tutorial which works perfectly (https://medium.com/@georgetsifrikas/embedding-uitextview-inside-uitableviewcell-9a28794daf01) to make my custom cell this:

class DetailTextTableViewCell: UITableViewCell, UITextViewDelegate {

    //Found below method for resizing UITextView and cell - https://medium.com/@georgetsifrikas/embedding-uitextview-inside-uitableviewcell-9a28794daf01
    @IBOutlet weak var memoryDescriptionTextView: UITextView!
    var textChanged: ((String) -> Void)?

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        memoryDescriptionTextView.delegate = self
        memoryDescriptionTextView.backgroundColor = UIColor.red
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

    //Found below method for resizing UITextView and cell - https://medium.com/@georgetsifrikas/embedding-uitextview-inside-uitableviewcell-9a28794daf01
    func textChanged(action: @escaping (String) -> Void) {
        self.textChanged = action
    }

    func textViewDidChange(_ textView: UITextView) {
        textChanged?(textView.text)
    }
}

Now I'm stuck with DetailTextTableViewCell being the UITextView's delegate, so I'm not sure how to make it update my memory object in the ViewController when the text changes. If anyone has any ideas or guidance it'd be much appreciated!

Thank you in advance.


Solution

  • declare this protocol above your cell DetailTextTableViewCell

    protocol CellDelegate {
      func textViewChanged(textView : UITextView)
    }
    

    add a delegate var in your DetailTextTableViewCell

    var delegate : CellDelegate?
    

    In the cell for row of your tableView assign self to delegate property of cell

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    ...
    cell.delegate = self
    

    }

    In your DetailTextTableViewCell add this line inside textViewDidChange

     func textViewDidChange(_ textView: UITextView) {
        textChanged?(textView.text)
        delegate?.textViewChanged(textView)
    }
    

    Now implement the delegate function in your view controller

    func textViewChanged(textView: UITextView) {
    
        }