问题
I have a custom cell, which is subclass of UITableViewCell
, call it Cell
.
I have added a UITableViewCell
through a storyboard to a tableview ( tableview's content is set to Dynamic Prototypes) and have set cells class to Cell
. Also I have set the reuse identifier appropriately.
The cell is defined in xib
, and I load it like this:
self.tableView.register(UINib(nibName: "Cell", bundle: nil), forCellReuseIdentifier: "CellIdentifier")
The cell itself has only two elements, and those are, one container view (a UIView
) and one image view (a UIImageView
).
Both of those elements are connected through outlets to the Cell
.
These two elements are positioned in a xib
using the Autolayout
constraints. Also, before the cell is about to display, I do something like this in my ViewController
(tried both cellForRowAtPath
and willDisplayCellForRowAtPath
methods):
cell.imageView.layer.cornerRadius = cell.imageView.layer.frame.height / 2.0
cell.imageView.layer.masksToBounds = true
cell.containerView.layer.cornerRadius = cell.containerView.layer.frame.height / 2.0
cell.containerView.layer.borderColor = UIColor.lightGray.cgColor
cell.containerView.layer.borderWidth = 1
and in both cases, at the time when I call UITableView's insertRows(atIndexPaths)
method, the cell is inserted, but it is not displayed properly. The next time, i insert new row (cell), the previous one is drawn correctly...And so on...
Here is how I insert cells (on a button click event):
func addCell(_ title: String) {
titles.append(title)
let indexPath = IndexPath(row: messages.count - 1, section: 0)
tableView.beginUpdates()
tableView.insertRows(at: [indexPath], with: .bottom)
tableView.endUpdates()
tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
}
So, how to have a cell drawn correctly in this case?
回答1:
The most elegant way of handling this is to subclass UIImageView
:
@IBDesignable
class RoundedImageView: UIImageView {
public override func layoutSubviews() {
super.layoutSubviews()
let radius = min(bounds.width, bounds.height) / 2
layer.cornerRadius = radius
}
}
Then use this RoundedImageView
instead of UIImageView
, and you'll automatically get this rounding, regardless of how the image view is resized dynamically by the auto layout engine. No manual tweaking of the radius is needed elsewhere.
And, if you want, by making it @IBDesignable
, if you put this in a separate "framework" target in your app (which we do so IB doesn't need to compile the whole project in order to render the @IBDesignable
target), you can also specify this as the base class for an image view in Interface Builder, and it will be rendered dynamically right in IB, too:
The above was a top level view in the scene, but it works the same if it's in a cell prototype or wherever. Just set the base class for the image view. Obviously, make sure you have "Clip to Bounds" selected on the "Attributes" inspector in IB, too.
By the way, you don’t have to make this designable if you don’t want to see the effect in IB, but you can if you want.
回答2:
Talked with you about this outside of StackOverflow, posting it here for others benefit.
I created a demo project that has the same issue you mentioned. I found a workaround by subclassing the cell and overriding layoutSubviews and setting the cornerRadius
using DispatchQueue.main.async {}
:
class TestCell: UITableViewCell {
@IBOutlet weak var colorImageView: UIImageView!
override func layoutSubviews() {
super.layoutSubviews()
DispatchQueue.main.async {
self.colorImageView.layer.cornerRadius = min(self.colorImageView.frame.width, self.colorImageView.frame.height) / 2
}
}
}
Another workaround I found was by using an observer(Swift 4) and a layoutIfNeeded()
call before setting the cornerRadius
class TestCell: UITableViewCell {
@IBOutlet weak var colorImageView: UIImageView!
var observer: NSKeyValueObservation?
override func awakeFromNib() {
super.awakeFromNib()
observer = self.observe(\.frame) { (cell, change) in
self.layoutIfNeeded()
self.colorImageView.layer.cornerRadius = min(self.colorImageView.frame.width, self.colorImageView.frame.height) / 2
}
}
}
来源:https://stackoverflow.com/questions/46504908/custom-cell-is-not-correctly-drawn-when-a-row-is-inserted-using-insertrowsatpat