Search code examples
iosswiftuitableviewautolayoutnslayoutconstraint

row height is not automatically updated


EDITED:

This is my custom cell class. It has a TextField and a TextView. Whatever I do I can't get the row height updated automatically. I know I can do it manually using heightForRowAt but I don't want to do that.

class customCell: UITableViewCell, UITextViewDelegate{

var didSetupConstraints = false

    var titleField : UITextField = {
        var textField = UITextField()
        textField.placeholder = "   Subject (optional)"
        textField.backgroundColor = UIColor.lightGray
        textField.translatesAutoresizingMaskIntoConstraints = false
        textField.layer.cornerRadius = 3
        textField.clipsToBounds = true

        return textField
    }()
    var messageView : UITextView = {
        var textView = UITextView()
        textView.text = "Add your email here"
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.backgroundColor = UIColor.red

        return UITextView()
    }()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        self.contentView.addSubview(titleField)
        self.contentView.addSubview(messageView)
        messageView.delegate = self
        addConstraints()

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func addConstraints(){
        contentView.addConstraints([titleField.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 23),titleField.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -18),titleField.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 18) ])
        titleField.addConstraint(NSLayoutConstraint(item: titleField, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 50))

         contentView.addConstraints([messageView.topAnchor.constraint(equalTo: titleField.bottomAnchor, constant: 11),messageView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -18),messageView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 18), messageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5)])
     messageView.addConstraint(NSLayoutConstraint(item: messageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 100))


    }

    override func layoutSubviews() {
        super.layoutSubviews()
        contentView.setNeedsLayout()
        contentView.layoutIfNeeded()
    }

override func updateConstraints() {
    if !didSetupConstraints {
        addConstraints()
        didSetupConstraints = true

    }

    super.updateConstraints()
}


    func textViewDidBeginEditing(_ textView: UITextView) {
        if textView.textColor == UIColor.lightGray {
            textView.text = nil
            textView.textColor = UIColor.black
        }
    }

    func textViewDidEndEditing(_ textView: UITextView) {
        if textView.text.isEmpty {
            textView.text = "Add your email here"
            textView.textColor = UIColor.lightGray
        }
    }



}

I have already seen this question and from what I have understood the things I need to do are:

  • Add tableView.estimatedRowHeight = 44.0 tableView.rowHeight = UITableViewAutomaticDimension which I have done in tableViewController
  • Add a bottom and top constraint: I have added a topAnchor to my TextField + a constraint between my TextField and TextView + a constraint between my TextView's bottomAnchor and the contentView bottomAnchor
  • I have added my constraints code into my updateConstraints() method.

Not sure if I need to do anything else, but I've done all three but it still doesn't work. I'm guessing that maybe my bottom/top constraints are not set up correctly. The current result that I get is (The textView isn't visible at all :(( )

enter image description here

yet what I expect to get is:

enter image description here

EDIT 2

See image:

enter image description here

After all the fixes, the only problem I have now is that the empty cells don't have the default size of 44, is it that the tableView is trying to be smart and adjusts the row height based on the last cell height?


Solution

  • A few things:

    1. updateConstraints can be called multiple times by the system, so use a flag to only add your constraints the first time.
    2. messageView.topAnchor.constraint(equalTo: titleField.topAnchor, constant: 11) should be messageView.topAnchor.constraint(equalTo: titleField.bottomAnchor, constant: 11)
    3. Try giving your messageView a height.
    4. As @Honey pointed out, textView was not returned in the initialization of messageView.
    5. About empty cell heights, if you don't want empty cells at all, just do tableView.tableFooterView = UIView() to get rid of them. It's probably the table view being smart about cell heights, like you said.