Reputation: 555
In an UITableViewCell, I have an UIView container, which contains a UIImageView on top and an UILabel on the bottom. When the UILabel does not contain text, I want to remove the UILabel and resize the UImageView to the bottom of my UIView container.
In my TableViewCell, I have this:
let x = imageViewPostPreview.bottomAnchor.constraint(equalTo: viewPreviewOverlay.topAnchor, constant: 0)
if postText == "" {
x.isActive = true
imageViewPostPreview.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner]
self.layoutSubviews()
self.layoutIfNeeded()
} else if postText != "" {
x.isActive = false
imageViewPostPreview.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]
self.layoutSubviews()
self.layoutIfNeeded()
}
}
This piece of code works on when the initial UITableViewCell is loaded, but when I scroll my UITableView, the cell loses the initial layout.
How do I setup the layout correctly, so the layout is kept on scroll?
Edit:
Initial cell, which is correct:
After scrolling, incorrect layout:
Upvotes: 0
Views: 141
Reputation: 91
A way you can have the cell calculate its size automatically, is to have constraints set inside the cell view for all directions on vertical axis. So, in your case the image view will have top, leading and trailing set to superview, and bottom to the label. The label will have leading and bottom to superview, and the top will be to the image view you set. It's important to set for vertical axis, since for table view we need it to calculate the height. This way the table view will know what to expect and can set height automatically.
After that you set tableView.rowHeight = UITableView.automaticDimension
. Or you can also set in the delegate method.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
After all this is in place, you will only need to give the right values to the cell subviews(in this case set image and text). You can do this inside cell for row function. A sample code will look something like this.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath)
let model = self.models[indexPath.row]
cell.imageViewPostPreview.image = model.image ?? nil
cell.postText.text = model.text ?? nil
return cell
}
This should work without any further need to calculate constraints and calling layouts to update. Hope this helps! You can also check this question.
Upvotes: 0
Reputation: 14397
Add this to prepareToReuse method
override func prepareForReuse() {
super.prepareForReuse()
let x = imageViewPostPreview.bottomAnchor.constraint(equalTo: viewPreviewOverlay.topAnchor, constant: 0)
if postText.isEmpty {
x.isActive = true
imageViewPostPreview.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner]
} else {
x.isActive = false
imageViewPostPreview.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]
}
self.layoutIfNeeded()
}
Note: Dont call layoutSubview
directly ... always try to call layoutifNeeded or setNeeedsLayout
Upvotes: 0