Gradient isn’t filling UITableViewCell

Viewed 302

I have coded a custom UITableView cell, and I’d like to use a gradient for its background. No matter what I try, the gradient doesn’t fill the cell or take on its rounded corners. Here’s what it looks like before gradient Before (I made the cell’s blue here so that you can see them), and here’s what it looks like after gradient:

After Here’s what I have so far:

import UIKit
import PlaygroundSupport

class ViewController: UITableViewController {
    override func numberOfSections(in tableView: UITableView) -> Int {
        return(5)
    }

    override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let view = UIView()
        view.backgroundColor = .white
        return view
    }

    override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        40
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        tableView.rowHeight = 200
        return 1
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardCell
        return cell
    }

    override func viewDidLoad(){
        super.viewDidLoad()
        tableView.register(CardCell.self, forCellReuseIdentifier: "CardCell")
    }
}

class CardCell: UITableViewCell {

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

        super.init(style: style, reuseIdentifier: reuseIdentifier)

        layer.masksToBounds = false
        layer.shadowOpacity = 0.23
        layer.shadowRadius = 12
        layer.shadowOffset = CGSize(width: 0, height: 0)
        layer.shadowColor = UIColor.black.cgColor
        layer.cornerRadius = 6

        var colorTop = UIColor()
        colorTop = .red
        var colorBottom = UIColor()
        colorBottom = .blue

        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [colorTop.cgColor, colorBottom.cgColor]
        gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
        gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
        gradientLayer.locations = [NSNumber(floatLiteral: 0.0), NSNumber(floatLiteral: 1.0)]
        gradientLayer.frame = self.bounds

        contentView.layer.insertSublayer(gradientLayer, at: 0)


        contentView.layer.cornerRadius = 100

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

PlaygroundPage.current.liveView = ViewController()
3 Answers

Here is what you need to do.. shift frame and corner radius to layoutIfNeeded

class CardCell: UITableViewCell {
    private lazy  var gradientLayer : CAGradientLayer = {
        let layer = CAGradientLayer()
        layer.colors = [UIColor.red, UIColor.blue].map{$0.cgColor}
        layer.startPoint = CGPoint(x: 0.5, y: 1.0)
        layer.endPoint = CGPoint(x: 0.5, y: 0.0)
        layer.locations = [NSNumber(floatLiteral: 0.0), NSNumber(floatLiteral: 1.0)]
        layer.frame = self.bounds
        layer.masksToBounds = true
       return layer
    }()

    override func layoutIfNeeded() {
        super.layoutIfNeeded()
        gradientLayer.frame = bounds
        contentView.layer.cornerRadius = bounds.maxY/2
    }

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

        super.init(style: style, reuseIdentifier: reuseIdentifier)

        layer.masksToBounds = false
        layer.shadowOpacity = 0.9
        layer.shadowRadius = 12
        layer.shadowOffset = CGSize(width: 0, height: 0)
        layer.shadowColor = UIColor.black.cgColor
        layer.cornerRadius = 6

        contentView.layer.insertSublayer(gradientLayer, at: 0)
        contentView.layer.masksToBounds = true


    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

PlaygroundPage.current.liveView = ViewController()

Result

enter image description here

Make your gradient layer accessible out at Cell scope and set its frame inside the layoutIfNeeded method:

class Cell: UITableViewCell {

    // ...

    let gradientLayer = CAGradientLayer()

    override func layoutIfNeeded() {
        super.layoutIfNeeded()

        gradientLayer.frame = bounds
    }
}

gradientLayer's frame need update

Just override func layoutSubviews()

class CardCell: UITableViewCell {

    let gradientLayer = CAGradientLayer()

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

        super.init(style: style, reuseIdentifier: reuseIdentifier)

        layer.masksToBounds = false
        layer.shadowOpacity = 0.23
        layer.shadowRadius = 12
        layer.shadowOffset = CGSize(width: 0, height: 0)
        layer.shadowColor = UIColor.black.cgColor
        layer.cornerRadius = 6

        var colorTop = UIColor()
        colorTop = .red
        var colorBottom = UIColor()
        colorBottom = .blue

        gradientLayer.colors = [colorTop.cgColor, colorBottom.cgColor]
        gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
        gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
        gradientLayer.locations = [NSNumber(floatLiteral: 0.0), NSNumber(floatLiteral: 1.0)]
        gradientLayer.frame = self.bounds

        contentView.layer.insertSublayer(gradientLayer, at: 0)


        contentView.layer.cornerRadius = 100

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        gradientLayer.frame = bounds
    }

}

Related