-1

Hi guys please am trying to make a view inherit from a gradient UIView with a background to it but for one or two reasons its not inheriting. Here is my code:

// The gradient class I want to be inherited from
class GradientView: UIView {

    var gradient = CAGradientLayer()

    override func awakeFromNib() {
        super.awakeFromNib()
        setupGradientView()
    }

    func setupGradientView(){
        gradient.frame = self.bounds
        gradient.colors = [UIColor.white.cgColor, UIColor.init(white:1.0, alpha: 0.0).cgColor]
        gradient.startPoint = CGPoint.zero
        gradient.endPoint = CGPoint(x: 0, y: 1)
        gradient.locations = [0.8,1.0]
        self.layer.addSublayer(gradient)
    }

}

let headerHolder: GradientView = {
        let view = GradientView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

//Where i set up the views
  func setupViews() {
    view.addSubview(headerHolder)
            headerHolder.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
            headerHolder.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
            headerHolder.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
            headerHolder.heightAnchor.constraint(equalToConstant: 80).isActive = true
}
Acetech
  • 398
  • 4
  • 16

3 Answers3

4

You need to call it inside

override init(frame: CGRect)

as awakeFromNib is not called in such init cases it's called when the view loaded from xib / stroryboard

and set the frame inside

override func layoutSubviews{}

as it's the place where the view gets it's correct bounds

//

class GradientView: UIView {

    var gradient = CAGradientLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupGradientView()
    } 
    override func layoutSubviews() {
        super.layoutSubviews() 
        gradient.frame = self.bounds
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    func setupGradientView(){

        gradient.colors = [UIColor.black.cgColor, UIColor.red.cgColor]
        gradient.startPoint = CGPoint.zero
        gradient.endPoint = CGPoint(x: 0, y: 1)
        gradient.locations = [0.8,1.0]
        self.layer.addSublayer(gradient)

    }

}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
2

The first problem is that you override awakeFromNib method, but it's never called, because you create your GradientView programmatically. You see, awakeFromNib is called onle the view loaded from Xib or Storyboard file. Here is quote from Apple Documentation.

The nib-loading infrastructure sends an awakeFromNib message to each object recreated from a nib archive, but only after all the objects in the archive have been loaded and initialized.

So if you want to create your view programmatically, you need to override init(frame: CGRect).

The second problem is that in setupGradientView method you're using self.bounds, but your view bounds has not been computed yet, because layout was not called. You may setup gradient layer frame at layoutSubviews method.

class GradientView: UIView {

    var gradient = CAGradientLayer()

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

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

    func setupGradientView() {
        let colorFrom = UIColor.white.cgColor
        let colorTo = UIColor.init(white:1.0, alpha: 0.0).cgColor
        gradient.colors = [colorFrom, colorTo]
        gradient.startPoint = CGPoint.zero
        gradient.endPoint = CGPoint(x: 0, y: 1)
        gradient.locations = [0.8, 1.0]
        self.layer.addSublayer(gradient)
    }

}

Hope it helps you.

Yury Imashev
  • 2,068
  • 1
  • 18
  • 32
0

The problem is that, because you created the CAGradientLayer directly, it doesn’t participate in UIKit’s layout system. You’re setting the gradient layer’s frame before the GradientView has been resized for the current device.

Instead of creating the gradient layer directly and making it a sublayer of the GradientView’s layer, tell GradientLayer that it’s own layer should be a CAGradientLayer:

class GradientView: UIView {
    override class var layerClass: AnyClass {
        return CAGradientLayer.self
    }

    var gradientLayer: CAGradientLayer {
        return self.layer as! CAGradientLayer
    }

    ...
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848