Fred Faust
Fred Faust

Reputation: 6790

Use custom view with XIB in IB uitableviewcell w/dynamic height

I have a cell that has a an area where the content can vary from other cells, (while other cell properties are the same) - I thought a custom view backed by a nib would work well in this case but am running into an issue using the custom view with cells where height is dynamic.

Storyboard:

enter image description here

Here is a UIViewController with a UITableView and a custom UITableViewCell, MessageTableViewCell, implemented like this:

class MessageTableViewCell: UITableViewCell {

@IBOutlet weak var avatar: UIImageView!
@IBOutlet weak var initials: UILabel!
@IBOutlet weak var timestamp: UILabel!
@IBOutlet weak var messageView: UIView!

override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
}

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

    // Configure the view for the selected state
}

}

In the view controller's cellForRowAtIndexPath method, I attempt to use the frame from the messageView (the white box in the cell on the view controller) to instantiate a UIView backed by a xib.

The custom view:

enter image description here

It's implementation:

class MessageView: NibLoadingView {

@IBOutlet weak var message: UILabel!

}

The NibLoadingView implementation: (credit: https://stackoverflow.com/a/40051928/4096655)

class NibLoadingView: UIView {

weak var view: UIView!

override init(frame: CGRect) {
    super.init(frame: frame)
    nibSetup()
}

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

private func nibSetup() {
    backgroundColor = .clear

    view = loadViewFromNib()
    view.frame = bounds
    view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    view.translatesAutoresizingMaskIntoConstraints = true

    addSubview(view)
}

private func loadViewFromNib() -> UIView {
    let bundle = Bundle(for: type(of: self))
    let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
    let nibView = nib.instantiate(withOwner: self, options: nil).first as! UIView

    return nibView
}
}

The cell for row implementation:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    guard let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell") as? MessageTableViewCell else {
        return UITableViewCell()
    }

    let frame = cell.messageView.frame
    let messageView = MessageView(frame: frame)
    messageView.message.text = messages[indexPath.row]
    cell.addSubview(messageView)

    return cell
}

Results in:

enter image description here

The short story is I'd like to share some common properties between what I would normally consider different cells and am trying to create custom views for the part of the cells that are different from each other, some of them have dynamic height. Thanks for reading.

Upvotes: 2

Views: 744

Answers (1)

J. Koush
J. Koush

Reputation: 1068

You do not need to create a custom view MessageView, instead you need to add the contents of MessageView in messageView which is the view that you added in your prototype cell MessageTableViewCell on the viewController and don't forget the outlets, and give the label inside the messageView constraints leading, top, trailing and bottom, lastly in your viewController instead of calling tableView(_:heightForRowAt:) call tableView(_:estimatedHeightForRowAt:) UITableViewDelegate method.

Upvotes: 1

Related Questions