Search code examples
swiftuitableviewcocoa-touchuiviewdrawrect

Unable to set the background colour of a UIView subclass used inside a UITableViewCell in Swift


Problem:

The custom view's background colour for each cell in my tableView always uses the initial colour set when declaring my statusColour variable, and the colour set dynamically in cellForRowAt IndexPath is always ignored.


This is my UIView subclass:

class SlantedView: UIView {

    var path: UIBezierPath!
    var backgroundColour: UIColor!

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

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

    func slantedView() {

         // Drawing code
         // Get Height and Width
         let layerHeight = CGFloat(90)
         let layerWidth = CGFloat(300)

         // Create Path
         let bezierPath = UIBezierPath()

         //  Points
         let pointA = CGPoint(x: 0, y: 0)
         let pointB = CGPoint(x: layerWidth, y: 89)
         let pointC = CGPoint(x: layerWidth, y: layerHeight)
         let pointD = CGPoint(x: 0, y: layerHeight)

         // Draw the path
         bezierPath.move(to: pointA)
         bezierPath.addLine(to: pointB)
         bezierPath.addLine(to: pointC)
         bezierPath.addLine(to: pointD)
         bezierPath.close()

         // Mask to Path
         let shapeLayer = CAShapeLayer()
         shapeLayer.path = bezierPath.cgPath
         layer.mask = shapeLayer
     }


    override func draw(_ rect: CGRect) {

        self.slantedView()

        self.backgroundColor = backgroundColour
        self.backgroundColor?.setFill()
        UIGraphicsGetCurrentContext()!.fill(rect)

    }
}



This is my custom cell:

class CustomTableViewCell: UITableViewCell {

    var statusColour: UIColor = {
        let colour = UIColor.red
        return colour
    }()


    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        let statusContainer = SlantedView()
        statusContainer.backgroundColour = self.statusColour
        self.addSubview(statusContainer)

    }

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

}



This is my cellForRow method:

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

    let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! CustomTableViewCell

    cell.statusColour = sampleData[indexPath.row].statusColour //Contains different colours

    return cell
}

The problem is definitely coming from the UIView subclass. According some prior research, it looks like the overridden draw function could be causing the issue.

I followed the advice given in some other Stack Overflow questions by adding these lines:

self.backgroundColor?.setFill()
UIGraphicsGetCurrentContext()!.fill(rect)

What could I be doing wrong?

Thanks in advance.


Solution

  • Add slantedView in awakeFromNib() method instead of init() and also use property observers to change the backgroung color of slantedView as shown below:

    class CustomTableViewCell: UITableViewCell {
    
        var statusContainer: SlantedView!
    
        var statusColour: UIColor? {
            didSet {
                guard let color = statusColour else {
                    statusContainer.backgroundColor = UIColor.black
                    return
                }
            statusContainer.backgroundColor = color
           }
        }
    
        override func awakeFromNib() {
            super.awakeFromNib()
            statusContainer = SlantedView(frame: self.bounds)
            self.addSubview(statusContainer)
        }
    }
    

    Lastly, remove last two lines from draw(_ rect: CGRect) method:-

     override func draw(_ rect: CGRect) {
        self.slantedView()
        self.backgroundColor = backgroundColour
    }