iosswiftuitableviewconstraintscartography

TableViewCell is constrained with Cartography and is not correct height


I am building a comments feature using a UITableView with dynamic cell heights. I am using the Cartography framework to set the constraints of the contents of each cell programmatically, as this table view is not setup within the storyboard.

I have a problem with the comment label overlapping cells below it. Cells that have a short comment string are looking good, here's an example SS:

CommentCell

I have set tableView.estimatedRowHeight = 60, cells are clipsToBounds = false

and

func tableView(_: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    UITableView.automaticDimension
}

Here are the constraints that I have set using the Cartography framework for the different subviews of the Cell:

 // User Image View
 constrain(self, userImageView) {
        $1.height == 36.0
        $1.width == 36.0
        $1.left == $0.left + 16.0
        $1.top == $0.top + 12.0
        $1.bottom == $0.bottom - 12.0 ~ UILayoutPriority(500)
 }
 
 // Comment Label
 constrain(self, commentLabel, userImageView) {
        $1.top == $2.top - 6.0
        $1.right == $0.right - (18.0 + Geometry.likeButtonWidth)
        $1.left == $2.right + Geometry.messageLabelLeftOffset
    }
 
 // Bottom view - ( comment_time / LikeCount / Reply )
 constrain(self.contentView, messageLabel, bottomView, userImageView) { contentView, msgLabel, bottomView, userImageView in
    
      bottomView.top == msgLabel.bottom
      bottomView.right == msgLabel.rightMargin
      bottomView.left == userImageView.right + Geometry.messageLabelLeftOffset
    
      // contentView.bottom == bottomView.bottom // very tall cell is overlapping cells below with this line
      // contentView.height == msgLabel.height + 20 // cell is twice as tall,  leaving large empty gap, but not overlapping
 }

The comment label has no bottom constraint set.

The bottonView has it's top set to the comment label's bottom, with no bottom constraint either. I figured this allows for the dynamic height to work. Using neither of the commented out constraints above in bottomView's constrain, it is still overlapping. I understand the overlap is caused by clipsToBounds on the cell being set to false, so the cell's height is the problem.

This is how that looks:

enter image description here

How do I get the cells height to fit the content?


Solution

  • So I realized all constraints needed to use the cell's self.contentView instead of just self, I had previously tried this and it didn't render correctly but that was because not all vertical constraints were present as you could see above. So this is how it should have been:

    // User Image View
    constrain(self.contentView, userImageView) {
        $1.height == 36.0
        $1.width == 36.0
        $1.left == $0.left + 16.0
        $1.top == $0.top + 12.0
        //$1.bottom == $0.bottom - 12.0 ~ UILayoutPriority(500) removed this
    }
    
    // Comment Label
    constrain(self.contentView, commentLabel, userImageView, bottomView) {
        $1.top == $2.top - 6.0
        $1.right == $0.right - (18.0 + Geometry.likeButtonWidth)
        $1.left == $2.right + Geometry.messageLabelLeftOffset
        $1.bottom == $3.top
    }
    
    // Bottom view - ( comment_time / LikeCount / Reply )
    
    constrain(self.contentView, messageLabel, bottomView, userImageView) { contentView, msgLabel, bottomView, userImageView in
        bottomView.top == msgLabel.bottom
        bottomView.right == msgLabel.rightMargin
        bottomView.left == userImageView.right + Geometry.messageLabelLeftOffset
        bottomView.bottom == contentView.bottom
    }