Custom cell is not correctly drawn when a row is inserted using insertRows(atPaths) method

纵然是瞬间 提交于 2021-02-07 23:29:32

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!