Search code examples
swiftuikitcellextension-methods

Problem addient gradients to a custom cell background swift


I've created a custom class to apply different gradients as you can see. But my problem is that I can't use it to add gradient to a custom cell

import UIKit

extension UIView {
    // MARK: - Creamos funcion para poder aplicar degrado vertical 2 colores
    func aplicarFondoDegradado() {
        let colorArriba =  UIColor(red: 255/255, green: 4/255, blue: 14/255, alpha: 1.0).cgColor
        let colorAbajo = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0).cgColor
        
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [colorArriba, colorAbajo]
        gradientLayer.locations = [0.0, 1.0]
        gradientLayer.frame = self.bounds
                
        self.layer.insertSublayer(gradientLayer, at:0)
    }
    func aplicarDegradadoCultural() {
        let colorInicio =  UIColor(red: 0/255, green: 56/255, blue: 255/255, alpha: 1.0).cgColor
        let colorFin = UIColor(red: 125/255, green: 195/255, blue: 226/255, alpha: 1.0).cgColor
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [colorInicio, colorFin]
        gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
        // Set end point.
        gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        gradientLayer.frame = self.bounds
        
        self.layer.insertSublayer(gradientLayer, at:0)
    }
    func aplicarDegradadoDeportes() {
        let colorInicio =  UIColor(red: 0/255, green: 56/255, blue: 255/255, alpha: 1.0).cgColor
        let colorFin = UIColor(red: 125/255, green: 195/255, blue: 226/255, alpha: 1.0).cgColor
     let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [colorInicio, colorFin]
        gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
    
        gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        gradientLayer.frame = self.bounds
        
        self.layer.insertSublayer(gradientLayer, at:0)
    }
}

And It works but my problem is that when I tried to apply to a dinamic cell the gradient it's not shown.

This is my code for the tableview controller which includes the custom cell controller:

import UIKit

class EventosCustomCellController: UITableViewCell {
    

    @IBOutlet weak var imEvento: UIImageView!
    
    @IBOutlet weak var txtNombreEvento: UILabel!
    
    @IBOutlet weak var txtFechaEvento: UILabel!
    
    @IBOutlet weak var txtEstadoEvento: UILabel!
}

class ListaEventosTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "Eventos"
        
        
    }

    // MARK: - Table view data source

    override func viewWillAppear(_ animated: Bool) {
        
        
    }
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return eventos.contarEventos()
    }

    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "prototipoCeldaEvento", for: indexPath) as! EventosCustomCellController
        
        let evento = eventos.buscarEventoPorID(id: indexPath.row)
        cell.layer.borderWidth = 1
        cell.layer.borderColor =  UIColor.black.cgColor
        cell.imageView?.layer.cornerRadius = 30
        
        cell.txtNombreEvento?.text = evento?.nombre
        cell.txtFechaEvento?.text = evento?.fecha
        cell.txtEstadoEvento?.text = evento?.tipo
        //THE PROBLEM IS HERE THE GRADIENT IS NOT SHOWN
        //THE PROBLEM IS HERE THE GRADIENT IS NOT SHOWN
        if evento?.tipo == "deportivo"{
            cell.aplicarDegradadoCultural()}
        else if evento?.tipo == "cultural"{
            cell.aplicarFondoDegradado()            }
        else{
            cell.aplicarDegradadoDeportes()}
        cell.layer.masksToBounds = true
           cell.layer.cornerRadius = 10
        
        cell.imEvento.loadFrom(URLAddress: (evento?.imagenes![0])!)
      
        cell.imEvento.layer.cornerRadius = 25
        cell.imEvento.clipsToBounds = true
        cell.imEvento.layer.borderWidth = 3
        cell.imEvento.layer.borderColor =  UIColor.white.cgColor
        return cell
    }
    

    
    // Override to support conditional editing of the table view.
    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return true
    }
   
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let celdaPulsada = tableView.indexPathForSelectedRow?.row
        eventos.devolverCeldaPulsada (id: celdaPulsada!)
    }}

Solution

  • You're doing a couple things wrong -- and, you'll find it much easier to use a custom "GradientView"

    Cells are reused... with your extension UIView approach, you are inserting another gradient layer every time the cell is used.

    Also, you're not guaranteed to have the correct frame at that point.

    Here is a very simple, basic custom "GradientView":

    class GradientView: UIView {
        
        var gradientLayer: CAGradientLayer!
        
        override class var layerClass: AnyClass {
            return CAGradientLayer.self
        }
        override init(frame: CGRect) {
            super.init(frame: frame)
            commonInit()
        }
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            commonInit()
        }
        func commonInit() -> Void {
            gradientLayer = self.layer as? CAGradientLayer
        }
        
    }
    

    Add a UIView to your cell's Content View in Storyboard, behind all of the labels, and constrain it to all 4 sides.

    Then, assign its Custom Class to GradientView, and connect it to your cell class just like the labels:

    @IBOutlet weak var gradientView: GradientView!
    

    Then, delete your extension UIView and move those gradient funcs to your cell, so it looks like this:

    class EventosCustomCellController: UITableViewCell {
        
        @IBOutlet weak var imEvento: UILabel!
        
        @IBOutlet weak var txtNombreEvento: UILabel!
        
        @IBOutlet weak var txtFechaEvento: UILabel!
        
        @IBOutlet weak var txtEstadoEvento: UILabel!
    
        @IBOutlet weak var gradientView: GradientView!
        
        func aplicarFondoDegradado() {
            let colorArriba =  UIColor(red: 255/255, green: 4/255, blue: 14/255, alpha: 1.0).cgColor
            let colorAbajo = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0).cgColor
            
            gradientView.gradientLayer.colors = [colorArriba, colorAbajo]
            gradientView.gradientLayer.locations = [0.0, 1.0]
    
            // start/end points
            gradientView.gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
            gradientView.gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
        }
        func aplicarDegradadoCultural() {
            let colorInicio =  UIColor(red: 0/255, green: 56/255, blue: 255/255, alpha: 1.0).cgColor
            let colorFin = UIColor(red: 125/255, green: 195/255, blue: 226/255, alpha: 1.0).cgColor
            
            gradientView.gradientLayer.colors = [colorInicio, colorFin]
    
            // start/end points
            gradientView.gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradientView.gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        }
        func aplicarDegradadoDeportes() {
            let colorInicio =  UIColor(red: 0/255, green: 56/255, blue: 255/255, alpha: 1.0).cgColor
            let colorFin = UIColor(red: 125/255, green: 195/255, blue: 226/255, alpha: 1.0).cgColor
    
            gradientView.gradientLayer.colors = [colorInicio, colorFin]
    
            // start/end points
            gradientView.gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradientView.gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        }
        
    }
    

    Now you can keep this in cellForRowAt:

        if evento?.tipo == "deportivo" {
            cell.aplicarDegradadoCultural()
        }
        else if evento?.tipo == "cultural" {
            cell.aplicarFondoDegradado()
        }
        else {
            cell.aplicarDegradadoDeportes()
        }
    

    and your cell's will set the gradient properties and size automatically.