Nitesh
Nitesh

Reputation: 2034

Horizontal Gradient to UIView

I'm trying to add Horizontal Gradient to UIView by following way

extension UIView {
    func insertHorizontalGradient(_ color1: UIColor, _ color2: UIColor) {
        let gradient = CAGradientLayer()
        gradient.colors = [color1.cgColor, color2.cgColor]
        gradient.transform = CATransform3DMakeRotation(CGFloat.pi / 2, 0, 0, 1)
        gradient.frame = bounds
        layer.insertSublayer(gradient, at: 0)
    }
}


    if let color1 = UIColor(hexString: "364190"), let color2 = UIColor(hexString: "699cf5"){
        self.statusBarView.insertHorizontalGradient(color1, color2)
    }

    if let color1 = UIColor(hexString: "182395"), let color2 = UIColor(hexString: "5497f0"){
        self.navigationBarView.insertHorizontalGradient(color1, color2)
    }

But on iPhone 6Plus its not getting applied to whole UIView. But on iPhone 6 its perfect.

enter image description here

Upvotes: 1

Views: 2371

Answers (3)

Sulthan
Sulthan

Reputation: 130200

You have to update the gradient everytime the frame of the view changes. Using an extension for it is not the best solution because you would have to override UIView.layoutSubviews in all UIView instances that use it. Instead, you could wrap the layer into a view:

@IBDesignable
public class GradientView: UIView {
    private func createGradient() -> CAGradientLayer {
        let gradient = CAGradientLayer()
        gradient.transform = CATransform3DMakeRotation(.pi / 2, 0, 0, 1)
        gradient.frame = bounds
        layer.insertSublayer(gradient, at: 0)
        return gradient
    }

    private var gradient: CAGradientLayer?

    @IBInspectable
    public var color1: UIColor? {
        didSet {
            updateColors()
        }
    }

    @IBInspectable
    public var color2: UIColor? {
        didSet {
            updateColors()
        }
    }

    required public init?(coder: NSCoder) {
        super.init(coder: coder)
        gradient = createGradient()
        updateColors()
    }

    override public init(frame: CGRect) {
        super.init(frame: frame)
        gradient = createGradient()
        updateColors()
    }

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

    private func updateColors() {
        guard
            let color1 = color1,
            let color2 = color2
        else {
            return
        }

        gradient?.colors = [color1.cgColor, color2.cgColor]
    }
}

and then:

extension UIView {
    func insertHorizontalGradient(_ color1: UIColor, _ color2: UIColor) -> GradientView {
        let gradientView = GradientView(frame: bounds)
        gradientView.color1 = color1
        gradientView.color2 = color2
        gradientView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        self.insertSubview(gradientView, at 0)
        return gradientView
    }
}

Note that I have made the view @IBDesignable, with both colors @IBInspectable, therefore you can actually preview the gradient in your storyboards/xibs.

Upvotes: 5

Shehata Gamal
Shehata Gamal

Reputation: 100549

You have to call it inside viewDidLayoutSubviews as it contains the correct frame not in viewDidLoad , also make sure that this function is called multiple times , so either wrap the code inside once bool , or set only the frame of the gradient inside it

Upvotes: 1

Jack
Jack

Reputation: 14379

Instead gradient.frame = bounds

try

 gradient.frame = CGRect(x: bounds.origin.x , y: bounds.origin.y, width: UIScreen.main.bounds.width , height: bounds.height)

as your view covering full width & this prevents viewDidLayoutSubviews multiple calls

Upvotes: 1

Related Questions