tolerate_Me_Thx
tolerate_Me_Thx

Reputation: 387

Dynamically adjust height of UITableViewCell fail in Swift 3

I have a customized UITableViewCell,and I want it to update height accroding my label text content.
But I try to use this code in my ViewController ViewDidLoad:

  tableView.register(ChatRightTextTableViewCell.self, forCellReuseIdentifier: ChatRightTextTableViewCell.identifier)
  tableView.estimatedRowHeight = 100.0
  tableView.rowHeight = UITableViewAutomaticDimension


it doesn't seem to update the height.
What's wrong with me about my cell constraint?
Thanks.

![cell constrain wrong like this.

import snapKit
import UIKit

class ChatRightTextTableViewCell: UITableViewCell {

static let identifier = "ChatRightTextTableViewCell"
var cellHeight: CGFloat = 0

var labelContent:UILabel = { ()->UILabel in
    let ui:UILabel = GeneratorLabel()
    ui.textColor = UIColor(red:0.20, green:0.20, blue:0.20, alpha:1.00)
    ui.backgroundColor = UIColor.white
    ui.font = defaultTextFont
    ui.numberOfLines = 0
    ui.lineBreakMode = NSLineBreakMode.byCharWrapping
    ui.layer.cornerRadius = defaultButtonRadius
    ui.layer.masksToBounds = true
    return ui
}()

var labelDatetime:UILabel = { ()->UILabel in
    let ui = GeneratorLabel()
    ui.font = defaultMessageTimeFont
    ui.textColor = defaultChatTimeColor
    ui.numberOfLines = 0
    return ui
}()

var icon:UIImageView = { ()->UIImageView in
    let ui = GeneratorAvatarImageView()
    ui.isUserInteractionEnabled = true
    return ui
}()

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

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

override func layoutSubviews() {
    super.layoutSubviews()
    loadVFL()
}

override func awakeFromNib() {
    super.awakeFromNib()
}

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

    // Configure the view for the selected state
}


func loadContent() {
    backgroundColor = defaultBackgroundColor
    selectionStyle = .none
    contentView.addSubview(labelContent)
    contentView.addSubview(labelDatetime)
    contentView.addSubview(icon)
}

func loadVFL() {

    let datetimeHeight:CGFloat = UIScreen.main.bounds.height*0.0195 //13

    let contentWidth:CGFloat = contentView.bounds.width*0.62  //254.5
    let iconLeftPadding:CGFloat = contentView.bounds.width*0.0266 //15
    let contentAndDatePadding:CGFloat = UIScreen.main.bounds.height*0.0089 //6
    let dateAndBottomPaddding:CGFloat = UIScreen.main.bounds.height*0.0090 //6
    let topPadding:CGFloat            = UIScreen.main.bounds.height*0.0149 //10
    let nameLabelBottomPadding:CGFloat = UIScreen.main.bounds.height*0.0075 //5

    let views = DictionaryOfInstanceVariables(self, objects: "labelContent","labelDatetime","icon")
    let metrics = ["padding":iconLeftPadding,"contentAndDatePadding":contentAndDatePadding,"dateAndBottomPaddding":dateAndBottomPaddding,"nameLabelBottomPadding":nameLabelBottomPadding,"topPadding":topPadding]

    labelContent.frame = CGRect(x: 0, y: 0, width: contentWidth, height: CGFloat.greatestFiniteMagnitude)
    labelContent.sizeToFit()

    icon.snp.makeConstraints { (make) -> Void in
        make.width.equalTo(defaultChatroomIconWidth)
        make.height.equalTo(defaultChatroomIconWidth)
        make.centerY.equalToSuperview()
    }

    labelDatetime.snp.makeConstraints { (make) in
        make.height.equalTo(datetimeHeight)
    }

    labelContent.backgroundColor = UIColor.red
    addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[labelContent]-padding-[icon]-padding-|", options: [], metrics: metrics, views: views))
    addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[labelDatetime]-padding-[icon]-padding-|", options: [], metrics: metrics, views: views))
    addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-topPadding-[labelContent]-contentAndDatePadding-[labelDatetime]-dateAndBottomPaddding-|", options: [], metrics: metrics, views: views))
    addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-topPadding-[icon]", options: [], metrics: metrics, views: views))
}
}

Upvotes: 0

Views: 889

Answers (3)

Pushpendra
Pushpendra

Reputation: 1521

Follows the below steps make your UITableCell height as dynamic according to the contents. That is very easy way to achieve all the steps.

  • Remove all the constraint from your UITableViewCell.
  • Remove all the programing constraint.
  • Now Set All the constraint from the UITableViewCell as given in diagram. Table View Constraint
  • Means give all constraint left, right, top and bottom.
  • If you want background of label then use your inspector of attribute from right side of your xCode.
  • if you want to use radios then use identity inspector tab and add USER DEFINED RUNTIME ATTRIBUTES key path -> layer.cornerRadius, type -> Number and value -> 5 / or what you want to give.
  • if you want to give number of line to label then give it from the Attribute Inspector as choose as multipleLine alignment.
  • If you don't want then give number of line 0 and choose as multipleLine alignment and check Automatically Adjust Font.

Now Lets constraint on programming

//Set Both line in view did upload function with same format 
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 100.0

Remove Function if you have use

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

Upvotes: 0

donkey
donkey

Reputation: 1448

Autolayout would usually provide a warning in the case that you were using a xib. Here's your issue: Content Hugging Priority & Content Compression Resistance.

Content Hugging Priority is a value that indicates wether the content of a view should have priority to stretch it's superview over the superview's own constraints. In this case, your label doesn't have priority over the cell content view to stretch it, so it's getting squished.

Content Compression Resistance is, similarly, a value that indicates wether the content of a view has priority to limit it's superview's frame based on it's own. For example, if your cell wanted to go to height 1, but your label had a higher content compression resistance and a height of, let's say 2, the cell would be forced to limit itself to two.

A good explanation of this is provided here.

Let's solve your problem then.

Either assign a bigger content hugging priority, or content compression resistance. In your case it seems like the label doesn't have priority to stretch the cell, so set the hugging priority:

labelDatetime.setContentHuggingPriority(500, for: .vertical)

Alternatively, experiment with content compression to give the cell priority over controlling it's own height, while respecting the label's boundaries.

Upvotes: 0

Sandeep Bhandari
Sandeep Bhandari

Reputation: 20379

Gotcha,

If u had used a xib, you would have noticed the warning, because u have coded it and placed labels its difficult to guess the issue :)

You are using two labels which basically decides the height of the cell based on the content they show. But because both have Same Content Hugging priority on vertical axis, providing only top and bottom constraint to these labels will not suffice.

You have to set the content hugging priority over vertical axis to one of the label (which ever u think will have smaller content obviously) to higher value to provide enough data to calculate the dynamic height of the cell.

Summary :

Simply set

labelDatetime.setContentHuggingPriority(252, for: .vertical)

or

var labelDatetime:UILabel = { ()->UILabel in
let ui = GeneratorLabel()
ui.font = defaultMessageTimeFont
ui.textColor = defaultChatTimeColor
ui.numberOfLines = 0
ui..setContentHuggingPriority(252, for: .vertical)
return ui
}()

Upvotes: 1

Related Questions