Search code examples
iosswiftuitableviewcell

Custom Table View Cell Drawing Wrong Height When Scrolling


I'm customizing my table view cell inside the willDisplayCell method. For some reason it is drawing some subviews with the wrong height while scrolling (see video). I can't figure out why...

override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {

    cell.contentView.backgroundColor=UIColor.clearColor()
    cell.reloadInputViews()

    let height = cell.frame.height - 15

    var whiteRoundedCornerView:UIView!
    whiteRoundedCornerView=UIView(frame: CGRectMake(7,10,self.view.bounds.width-14,height))
    whiteRoundedCornerView.backgroundColor=getColorByID(colorID!)
    whiteRoundedCornerView.layer.masksToBounds=false

    whiteRoundedCornerView.layer.shadowOpacity = 1.55;

    whiteRoundedCornerView.layer.shadowOffset = CGSizeMake(1, 0);
    whiteRoundedCornerView.layer.shadowColor=UIColor.grayColor().CGColor

    whiteRoundedCornerView.layer.cornerRadius=5.0
    whiteRoundedCornerView.layer.shadowOffset=CGSizeMake(-1, -1)
    whiteRoundedCornerView.layer.shadowOpacity=0.5

    whiteRoundedCornerView.layer.shouldRasterize = true
    whiteRoundedCornerView.layer.rasterizationScale = UIScreen.mainScreen().scale


    if cell.contentView.subviews.count < 6 {  //  to avoid multible subview adding when scrolling...

        cell.contentView.addSubview(whiteRoundedCornerView)
        cell.contentView.sendSubviewToBack(whiteRoundedCornerView)

    }
}

Here is a video of the issue:

https://vid.me/QeV0

Update:

I also tried to move the code to layoutSubviews but still the same issue...

override func layoutSubviews() {
    super.layoutSubviews()

    let height = self.frame.height - 15

    var whiteRoundedCornerView:UIView!
    whiteRoundedCornerView=UIView(frame: CGRectMake(7,10,UIScreen.mainScreen().bounds.width-14,height))
    whiteRoundedCornerView.backgroundColor=UIColor.greenColor()//getColorByID(colorID!)
    whiteRoundedCornerView.layer.masksToBounds=false

    whiteRoundedCornerView.layer.shadowOpacity = 1.55;

    whiteRoundedCornerView.layer.shadowOffset = CGSizeMake(1, 0);
    whiteRoundedCornerView.layer.shadowColor=UIColor.grayColor().CGColor

    whiteRoundedCornerView.layer.cornerRadius=5.0
    whiteRoundedCornerView.layer.shadowOffset=CGSizeMake(-1, -1)
    whiteRoundedCornerView.layer.shadowOpacity=0.5

    whiteRoundedCornerView.layer.shouldRasterize = true
    whiteRoundedCornerView.layer.rasterizationScale = UIScreen.mainScreen().scale


    if self.contentView.subviews.count < 6 {              

        self.contentView.addSubview(whiteRoundedCornerView)
        self.contentView.sendSubviewToBack(whiteRoundedCornerView)

    }
}

If i don't check the tableview.subviews.count it will add tons of subviews to the cell while scrolling.

I want to change the height of the existing subview when the cell is reused.


Solution

  • You have a check to not add the subviews multiple times. When that case happens you already have added the subviews earlier but their height may now be wrong and you must update them.

    UITableView reuses cells so a new cell with different height might already contain your subviews but with the wrong height since you don't update it.

    You should cleanly separate the set-up of your subview and the layout like so:

    class MyCell: UITableViewCell {
    
        private let whiteRoundedCornerView = UIView()
    
    
        override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
    
            setUp()
        }
    
    
        required init?(coder: NSCoder) {
            super.init(coder: coder)
    
            setUp()
        }
    
    
        override func layoutSubviews() {
            super.layoutSubviews()
    
            let bounds = self.bounds
    
            var whiteRoundedCornerViewFrame = CGRect()
            whiteRoundedCornerViewFrame.origin.x = 7
            whiteRoundedCornerViewFrame.origin.y = 10
            whiteRoundedCornerViewFrame.size.width = bounds.width - 7 - whiteRoundedCornerViewFrame.origin.x
            whiteRoundedCornerViewFrame.size.height = bounds.height - 5 - whiteRoundedCornerViewFrame.origin.y
            whiteRoundedCornerView.frame = whiteRoundedCornerViewFrame
        }
    
    
        private func setUp() {
            setUpWhiteRoundedCornerView()
        }
    
    
        private func setUpWhiteRoundedCornerView() {
            let child = whiteRoundedCornerView
            child.backgroundColor = .greenColor()
    
            let layer = child.layer
            layer.cornerRadius = 5.0
            layer.rasterizationScale = UIScreen.mainScreen().scale
            layer.shadowColor = UIColor.grayColor().CGColor
            layer.shadowOffset = CGSize(width: -1, height: -1)
            layer.shadowOpacity = 0.5
            layer.shouldRasterize = true
    
            insertSubview(child, atIndex: 0)
        }
    }