UITableView Custom Cell Auto-Resizing with TextView & ImageView

35 Views Asked by At

I have a table view with a custom cell that will display comments from users. In the view conrtoller where the table view is located, I make a network call to fetch the comments and the related images for each comment, I then calculate the aspect ratio of the images and pass it along with the comment to the custom cell in cellForRowAt method.

I pass the above information by calling a method in the custom cell which also sets the constraints for both the textView and the ImageView.

My goal is to have the textView start from top and leading with 5 buffer and be trailing the ImageView's leading with 5 buffer as well. The ImageView will have a fixed height of 70 and calculate the width based on the passed aspect ratio.

I want the cell to auto expand depending on the textView length while also at the same time have the ImageView maintain 5 points from the bottom in case the textView is short.

Below are the constraints I call in init of the custom cell:

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        contentView.backgroundColor = .red
        contentView.addSubview(commentTextView)
        contentView.addSubview(relatedImage)
        NSLayoutConstraint.activate([
            commentTextView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
            commentTextView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5),
            commentTextView.trailingAnchor.constraint(equalTo: relatedImage.leadingAnchor, constant: -5),
            commentTextView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            
            relatedImage.heightAnchor.constraint(equalToConstant: 70),
            relatedImage.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
            relatedImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5),
            relatedImage.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: -5),
        ])
        aspectConstraint = relatedImage.widthAnchor.constraint(equalTo: self.relatedImage.heightAnchor, multiplier: 1)
    }

Below is a function in the custom cell that I call from cellForRowAt to pass the UIImages along with the aspect ratio:

func setUpImage(aspectRatio: Double, image: UIImage) {
        relatedImage.image = image
        aspectConstraint.isActive = false
        relatedImage.widthAnchor.constraint(equalTo: self.relatedImage.heightAnchor, multiplier: aspectRatio).isActive = true
        contentView.layoutIfNeeded()
    }

I also have the textView scroll disabled and the tableView heightForRowAt set to auto dimensions and estimated row height set at 80.

Problem I am facing is I am unable to satisfy the below constraints at the same time:

1- commentTextView must autoresize the tableview cell depending on its content.

2- ImageView must have a height of 70 and be 5 points from top.

3- ImageView must at least maintain 5 points from the bottom of the cell meaning if the commentTextView is short I don't want the cell to shrink to the point of clipping the imageView.

Below is the full custom cell class if that helps

class CommentCell: UITableViewCell {

    
    let usernameLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 15, weight: .semibold)
        label.textColor = .white
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let timeAgoLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 12, weight: .regular)
        label.textColor = .white
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let commentTextView: UITextView = {
        let textView = UITextView()
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.textColor = .white
        textView.backgroundColor = .red
        textView.text = "Send a comment"
        textView.isEditable = false
        textView.isScrollEnabled = false
        textView.alpha = 1
        textView.keyboardDismissMode = .none
        textView.returnKeyType = .send
        textView.isHidden = false
        textView.layer.borderColor = UIColor.yellow.cgColor
        textView.layer.borderWidth = 1
        textView.contentMode = .left
        
        return textView
    }()
    
    private let relatedImage: UIImageView = {
        let vw = UIImageView()
        vw.contentMode = .scaleAspectFit
        vw.translatesAutoresizingMaskIntoConstraints = false
        vw.isUserInteractionEnabled = true
        vw.clipsToBounds = true
        vw.layer.masksToBounds = true
        
        return vw
    }()
    
    var aspectConstraint: NSLayoutConstraint!
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        contentView.backgroundColor = .red
        contentView.addSubview(commentTextView)
        contentView.addSubview(relatedImage)
        NSLayoutConstraint.activate([
            commentTextView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
            commentTextView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5),
            commentTextView.trailingAnchor.constraint(equalTo: relatedImage.leadingAnchor, constant: -5),
            commentTextView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            
            relatedImage.heightAnchor.constraint(equalToConstant: 70),
            relatedImage.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
            relatedImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5),
            relatedImage.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: -5),
        ])
        aspectConstraint = relatedImage.widthAnchor.constraint(equalTo: self.relatedImage.heightAnchor, multiplier: 1)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func setUpImage(aspectRatio: Double, image: UIImage) {
        relatedImage.image = image
        aspectConstraint.isActive = false
        relatedImage.widthAnchor.constraint(equalTo: self.relatedImage.heightAnchor, multiplier: aspectRatio).isActive = true
        contentView.layoutIfNeeded()
    }
    
}
0

There are 0 best solutions below