-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
}

3 Answers 3

5

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)

    }

}
Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

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
    }

    ...
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.