Seto
Seto

Reputation: 1666

Why gradient layer in UITableViewCell not cover entire frame?

I try to make a standard gradient top-bottom with long UIView. But it's not full. The nib is part of UITableViewCell, so I don't have access to viewDidLayoutSubviews() as in this thread.

enter image description here

I've tried to call contentView.layoutIfNeeded() from the code version of this view. I called it when UITableView cellForRowAtIndexPath gets called. But it's no effect.

I prepare the gradient in awakeFromNib().

let colors = [
            UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1.0).cgColor,
            UIColor(red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 1.0).cgColor]
let gradient = CAGradientLayer()
gradient.frame = gradientView.bounds
gradient.colors = colors
gradientView.layer.insertSublayer(gradient, at: 0) 

Is there something wrong with my code?

Upvotes: 5

Views: 3799

Answers (2)

clemens
clemens

Reputation: 17712

You should use view's boundsinstead of frame, because your layer is inside of the view, and the frame may have an offset.

The layout of the view is changed after awakeFromNib. So you should resize the layer in layoutSubviews of the view. For this create a property gradient and:

let gradient: CAGradientLayer = CAGradientLayer()

override func awakeFromNib() {
    ...
    let colors = [
                UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1.0).cgColor,
                UIColor(red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 1.0).cgColor]
    gradient.frame = bounds
    gradient.colors = colors
    gradientView.layer.insertSublayer(gradient, at: 0) 
    ...
}

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

EDIT: An alternative is a custom view with own layer class:

public class GradientLayer: UIView {
    @IBInspectable var startColor: UIColor! = UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1.0)
    @IBInspectable var endColor: UIColor! = UIColor(red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 1.0)

    override class var layerClass : AnyClass {
        return CAGradientLayer.self
    }
    override func awakeFromNib() {
        super.awakeFromNib()
        let colors = [ startColor.cgColor, endColor.cgColor ]
        if let gradient = self.layer as? CAGradientLayer {
            gradient.colors = colors
        }
    }
}

This is more elegant, because you can replace the static colors with IB inspectables, and you have a reusable component view.

Upvotes: 9

Svitlana
Svitlana

Reputation: 3006

 override func layoutSubviews() {
        super.layoutSubviews()

        if let gradient = baseView.layer.sublayers?[0] as? CAGradientLayer {
            gradient.frame = self.bounds
        }
 }

Upvotes: 6

Related Questions