Reputation: 569
I am practicing with gradient backgrounds for a bigger app and created this dummy app to simplify the concept. The view has a 50/50 gradient background and 2 rows of colored buttons.
I want the user to be able to play with colors of the gradient by tapping upper and lower buttons, so that gradient background changes accordingly to buttons color.
ViewController's code is following:
import UIKit
class ViewController: UIViewController {
var currentUpperColor = UIColor.black
var currentLowerColor = UIColor.white
override func viewDidLoad() {
super.viewDidLoad()
setGradientBackground(lowerColor: currentLowerColor, upperColor: currentUpperColor)
}
func setGradientBackground(lowerColor: UIColor, upperColor: UIColor) {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = view.bounds
gradientLayer.colors = [lowerColor.cgColor, upperColor.cgColor]
gradientLayer.locations = [0.5, 1.0]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 0.0)
view.layer.insertSublayer(gradientLayer, at: 0)
}
@IBAction func upperColorPicked(_ sender: UIButton) {
currentUpperColor = sender.backgroundColor!
setGradientBackground(lowerColor: currentLowerColor, upperColor: currentUpperColor)
}
@IBAction func lowerColorPicked(_ sender: UIButton) {
currentLowerColor = sender.backgroundColor!
setGradientBackground(lowerColor: currentLowerColor, upperColor: currentUpperColor)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
But when the app runs, nothing happens when buttons are tapped. I understand some kind of view redraw should occur, but I'm not sure how to call it.
Upvotes: 2
Views: 1240
Reputation: 115
The code shows that you have declared the CAGradientLayer() as a local variable. So it means that every time you want to update the button a gradientLayer gets inserted/ added to the view. The layer must be added only once and the colors must be updated according to the button actions.
var currentUpperColor = UIColor.black
var currentLowerColor = UIColor.white
let gradientLayer = CAGradientLayer()
override func viewDidLoad() {
super.viewDidLoad()
setGradientBackground(lowerColor: currentLowerColor, upperColor: currentUpperColor)
}
func setGradientBackground(lowerColor: UIColor, upperColor: UIColor) {
gradientLayer.frame = view.bounds
gradientLayer.colors = [lowerColor.cgColor, upperColor.cgColor]
gradientLayer.locations = [0.5, 1.0]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 0.0)
view.layer.insertSublayer(gradientLayer, at: 0)
}
@IBAction func upperColorPicked(_ sender: UIButton) {
currentUpperColor = sender.backgroundColor!
gradientLayer.colors = [currentLowerColor.cgColor, currentUpperColor.cgColor]
}
@IBAction func lowerColorPicked(_ sender: UIButton) {
currentLowerColor = sender.backgroundColor!
gradientLayer.colors = [currentLowerColor.cgColor, currentUpperColor.cgColor]
}
Upvotes: 0
Reputation: 79646
I tried your code and here it seems found working with following changes:
import UIKit
class GradientController: UIViewController {
@IBOutlet weak var vwButtonContainer: UIView!
var currentUpperColor = UIColor.black
var currentLowerColor = UIColor.white
var gradientLayer = CAGradientLayer()
override func viewDidLoad() {
super.viewDidLoad()
setGradientBackground(lowerColor: currentLowerColor, upperColor: currentUpperColor)
}
func setGradientBackground(lowerColor: UIColor, upperColor: UIColor) {
if gradientLayer != nil {
gradientLayer.removeFromSuperlayer()
}
gradientLayer = CAGradientLayer()
gradientLayer.frame = view.bounds
gradientLayer.colors = [lowerColor.cgColor, upperColor.cgColor]
gradientLayer.locations = [0.5, 1.0]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 0.0)
let sublayersCount = view.layer.sublayers?.count ?? 0
view.layer.insertSublayer(gradientLayer, at: UInt32(sublayersCount))
view.layer.layoutSublayers()
view.bringSubview(toFront: vwButtonContainer)
}
@IBAction func upperColorPicked(_ sender: UIButton) {
currentUpperColor = sender.backgroundColor!
setGradientBackground(lowerColor: currentLowerColor, upperColor: currentUpperColor)
}
@IBAction func lowerColorPicked(_ sender: UIButton) {
currentLowerColor = sender.backgroundColor!
setGradientBackground(lowerColor: currentLowerColor, upperColor: currentUpperColor)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Storyboard Layout:
Result:
Upvotes: 1
Reputation: 20379
Reason
view.layer.insertSublayer(gradientLayer, at: 0)
Will always insert the gradient layer at index 0. Initially u created a layer with black and white color and added at position 0. Now when user chooses a new color you create a new layer and add it index 0 making black and white layer to be at index 1. Hence only black and white layer will always appear
Solution:
Remove old layer and add new layer.
Step 1:
Declare gradientLayer as instance variable
class ViewController: UIViewController {
var gradientLayer = CAGradientLayer()
....
}
Step 2:
In IBAction remove old layer and add new layer
@IBAction func upperColorPicked(_ sender: UIButton) {
self.gradientLayer.removeFromSuperlayer()
currentUpperColor = sender.backgroundColor!
setGradientBackground(lowerColor: currentLowerColor, upperColor: currentUpperColor)
}
@IBAction func lowerColorPicked(_ sender: UIButton) {
self.gradientLayer.removeFromSuperlayer()
currentLowerColor = sender.backgroundColor!
setGradientBackground(lowerColor: currentLowerColor, upperColor: currentUpperColor)
}
Solution 2:(Not the preferred one)
If you want to stack up layers with different colors (I don't personally see any reason for doing so, but if thats what you want then) you can use
view.layer.insertSublayer(CALayer(), at: UInt32(view.layer.sublayers?.count ?? 0))
So modify your setGradientBackground
as
func setGradientBackground(lowerColor: UIColor, upperColor: UIColor) {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = view.bounds
gradientLayer.colors = [lowerColor.cgColor, upperColor.cgColor]
gradientLayer.locations = [0.5, 1.0]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 0.0)
view.layer.insertSublayer(CALayer(), at: UInt32(view.layer.sublayers?.count ?? 0))
}
Upvotes: 4