Reputation: 10738
I'm trying to apply a gradient to a view which is constraint to the top, left and right of the main screen but for some reason the gradient doesn't cover the whole width of the view that is applied to (see the yellow in the picture).
class ViewController: UIViewController {
@IBOutlet weak var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let gradient = CAGradientLayer()
gradient.colors = [UIColor.blue.cgColor, UIColor.white.cgColor]
gradient.startPoint = CGPoint(x:00, y:00)
gradient.endPoint = CGPoint(x:0, y:0.6)
gradient.frame = myView.bounds
myView.clipsToBounds = true
myView.layer.insertSublayer(gradient, at: 0)
}
}
What am I doing wrong?
Upvotes: 8
Views: 9030
Reputation: 99
simply put you gredient layer in main thred like this
DispatchQueue.main.async {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.viewGredient.bounds
gradientLayer.colors = [UIColor.black.cgColor, UIColor.white.cgColor]
gradientLayer.locations = [0.0, 1.0]
self.viewGredient.layer.addSublayer(gradientLayer)
}
Upvotes: 3
Reputation: 119380
You can turn it to a UIView
. So it will resize automatically and can be seen directly in the Storyboard:
@IBDesignable
final class GradientView: UIView {
@IBInspectable var firstColor: UIColor = .clear { didSet { updateView() } }
@IBInspectable var secondColor: UIColor = .clear { didSet { updateView() } }
@IBInspectable var startPoint: CGPoint = CGPoint(x: 0, y: 0) { didSet { updateView() } }
@IBInspectable var endPoint: CGPoint = CGPoint(x: 1, y: 1) { didSet { updateView() } }
override class var layerClass: AnyClass { get { CAGradientLayer.self } }
override func layoutSubviews() {
super.layoutSubviews()
updateView()
layer.frame = bounds
}
private func updateView() {
let layer = self.layer as! CAGradientLayer
layer.colors = [firstColor, secondColor].map {$0.cgColor}
layer.startPoint = startPoint
layer.endPoint = endPoint
}
}
Upvotes: 2
Reputation: 482
You can simplify it by CustomClass with one line of code
class GradientView: UIView {
override class var layerClass: Swift.AnyClass {
return CAGradientLayer.self
}
}
// MARK: Usage
@IBOutlet weak var myView: GradientView!
guard let gradientLayer = myView.layer as? CAGradientLayer else { return }
gradient.colors = [UIColor.blue.cgColor, UIColor.white.cgColor]
gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
gradient.endPoint = CGPoint(x:0, y:0.6)
Upvotes: 0
Reputation: 131426
The problem is likely that you are adding the gradient layer in viewDidLoad()
. A view doesn't get set to it's final size until after viewDidLoad()
.
Your view controller may be set up in your XIB/Storyboard for a different screen-size than you're running it on. (Say you have it set to iPhone SE size, but you're running it on a 6. The 6's screen is a little wider, so the layer will get set to the width of the iPhone SE, when the view is first loaded. Then the view will be resized, but the layer's size will never be adjusted.)
You should implement the UIViewController method viewDidLayoutSubviews()
, and in that method, adjust the layer's frame:
override func viewDidLayoutSubviews() {
gradientLayer.frame = self.view.bounds
}
That way if the view gets resized (due to auto-rotation, for example) the gradient layer will be automatically adjusted accordingly.
As pointed out by Sulthan, changes to a layer's frame are animated by default. You should probably wrap the frame change in a CATransaction.begin
/CATransaction.end
and disable actions, like below:
override func viewDidLayoutSubviews() {
CATransaction.begin()
CATransaction.setDisableActions(true)
gradientLayer.frame = self.view.bounds
CATransaction.commit()
}
Upvotes: 30
Reputation: 3428
You needn't set the start and end point, given your goal is to have the gradient span the entire view. You're already setting that with `
gradientLayer.frame = self.view.bounds
`
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myView: UIView!
var gradientLayer: CAGradientLayer!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
createGradientLayer()
}
func createGradientLayer() {
gradientLayer = CAGradientLayer()
gradientLayer.frame = self.view.bounds
gradientLayer.colors = [UIColor.blueColor().CGColor, UIColor.whiteColor().CGColor]
self.view.layer.addSublayer(gradientLayer)
}
}
Upvotes: 1