[LearnIOS]調色大師 調一個鋼鐵人頭盔
LearnIOS
這次的實作方向是一個可以調整RGB顏色的APP
上網找了一下圖片找了一個鋼鐵人的頭盔
左邊的是原圖,不過圖源是網路在教如何畫畫的網站,所以已經都去背完成,只剩下線條的部分,一直在思考該如何填滿周圍及把藍色線條改成黑色,Mac內建的Preview無法做到這個事情,於是爬了一下文找到一個程式叫做Paintbrush
選擇第一個就可以了,使用起來有點類似Windows的小畫家,輕鬆上手,於是右邊的就是結果,這樣子在後面改變顏色的時候就只會在面具部分變色
這樣子事前準備也就完成了
這是我的分層圖,主要就是由3個imageView來呈現,
最下層的是上完色的鋼鐵人面罩彩色原始圖,
中間層是空白的imageView,也就是大部分的變動也都在這裡發生,產生自訂的RGB色層及CAGradientLayer
最上層就是增加黑色填滿效果的原圖,
準備好後再來就是實作程式碼
首先是連結各種的IBOutlet
@IBOutlet weak var imageView: UIImageView!@IBOutlet weak var colorView: UIImageView!@IBOutlet weak var originalView: UIImageView!@IBOutlet weak var redSlider: UISlider!@IBOutlet weak var greenSlider: UISlider!@IBOutlet weak var blueSlider: UISlider!@IBOutlet weak var alphaSlider: UISlider!@IBOutlet weak var gradientSlider: UISlider!@IBOutlet weak var cornerRadiusSlider: UISlider!@IBOutlet weak var redLabel: UILabel!@IBOutlet weak var greenLabel: UILabel!@IBOutlet weak var blueLabel: UILabel!@IBOutlet weak var alphaLabel: UILabel!@IBOutlet weak var cornerRadiusLabel: UILabel!@IBOutlet weak var redSliderSwitch: UISwitch!@IBOutlet weak var greenSliderSwitch: UISwitch!@IBOutlet weak var blueSliderSwitch: UISwitch!@IBOutlet weak var gradientSwitch: UISwitch!
再來連結UIslider,讓調整Slider時顏色可以改變,彼得潘上課的時候說可以把所有連結到同一個裡面,因為它們都是做一樣的事情,還有讓UILabel們可以顯示數值
@IBAction func sliderChanged(_ sender: UISlider) {redLabel.text = String(format: “%.2f”, redSlider.value)greenLabel.text = String(format: “%.2f”, greenSlider.value)blueLabel.text = String(format: “%.2f”, blueSlider.value)alphaLabel.text = String(format: “%.2f”, alphaSlider.value)imageView.backgroundColor = UIColor(red: CGFloat(redSlider.value), green: CGFloat(greenSlider.value), blue: CGFloat(blueSlider.value), alpha: CGFloat(alphaSlider.value))}
UISwitch的部分就比較簡單,本來是用ifelse來寫後來在最後修改程式碼時偶然看到一些文章,就換成這樣
@IBAction func switchb(_ sender: Any) {redSlider.isEnabled = redSliderSwitch.isOngreenSlider.isEnabled = greenSliderSwitch.isOnblueSlider.isEnabled = blueSliderSwitch.isOn}
再來就是讓我卡關最久的CAGredientLayer,下面是我本來的程式碼
@IBAction func gradientSlider(_ sender: UISlider) {let gradientLayer = CAGradientLayer()gradientLayer.frame = imageView.boundsgradientLayer.colors = [UIColor.black.cgColor , UIColor(red: CGFloat(redSlider.value), green: CGFloat(greenSlider.value), blue: CGFloat(blueSlider.value), alpha: CGFloat(alphaSlider.value)).cgColor,UIColor.black.cgColor]gradientLayer.startPoint = CGPoint(x: 0, y: 0)gradientLayer.endPoint = CGPoint(x: 1, y: 1)gradientLayer.cornerRadius = CGFloat(cornerRadiusSlider.value)gradientLayer.locations = [0, NSNumber(value: gradientSlider.value), 1]imageView.layer.addSublayer(gradientLayer)} 這個slider的程式碼不好的不要參考!!!!!
但在執行APP時,漸層改變越多次,整個APP執行會越來越卡,我一直找不到原因,仔細思考下覺得說可能這樣執行起來,是每調整一次漸層效果,就會增加一個CAGradientLayer,所以相對的會越來越卡,所以前面加一行程式碼每次調整時都先把imageView的所有layer刪掉,問題就解決了
imageView.layer.sublayers = nil
但後來在新增控制gradientSlider的switch時發現,打開開關時要新增一個layer,程式碼會重複並執行一模一樣的事情,彼得潘說過越厲害的工程師會用越少的程式碼來達成一樣的事情,最後在調整siwtch的時候把建立CAGradient的程式碼改到UISwitch裡面
@IBAction func gradientChanged(_ sender: UISwitch) {if gradientSwitch.isOn == true, imageView.layer.sublayers == nil {let gradientLayer = CAGradientLayer()gradientLayer.frame = imageView.boundsgradientLayer.colors = [UIColor.black.cgColor , UIColor(red: CGFloat(redSlider.value), green: CGFloat(greenSlider.value), blue: CGFloat(blueSlider.value), alpha: CGFloat(alphaSlider.value)).cgColor,UIColor.black.cgColor]gradientLayer.startPoint = CGPoint(x: 0, y: 0)gradientLayer.endPoint = CGPoint(x: 1, y: 1)gradientLayer.cornerRadius = CGFloat(cornerRadiusSlider.value)gradientLayer.locations = [0, 0.5, 1]imageView.layer.addSublayer(gradientLayer)gradientSlider.isEnabled = gradientSwitch.isOn}else{gradientSlider.isEnabled = gradientSwitch.isOnimageView.layer.sublayers = nil}}
但是呢,又發生一個問題,在調整gradientSlider時,沒辦法存取到gradientLayer這個參數,終於參考了學長姐的文章中找到了方法,最後把gradientSlider的程式碼改成這樣
@IBAction func gradientSlider(_ sender: UISlider) {if let gradientLayer = imageView.layer.sublayers?[0] as? CAGradientLayer {gradientLayer.locations = [0, NSNumber(value: sender.value),1]}}
就我的理解是說 指定imageView的layer的第一個sublayer並存到常數裡,但是這個常數是optional,可能不會存在,因此在optional Binding 後,指定轉型成CAGradientLayer,如果成功讀取到並轉型成功,就存到gradientLayer這個常數,因此就可以讀到imageView中的gradientLayer,也就是我們創造的漸層
最後要來增加一個隨機的按鈕,來隨機改變RGB顏色,綜合我上面提到的方法,程式碼如下,這樣連漸層的顏色也可以一起隨機
@IBAction func random(_ sender: Any) {let rvalue = Float.random(in: 0…1)let gvalue = Float.random(in: 0…1)let bvalue = Float.random(in: 0…1)if redSliderSwitch.isOn == true{redSlider.value = rvalue}if greenSliderSwitch.isOn == true{greenSlider.value = gvalue}if blueSliderSwitch.isOn == true{blueSlider.value = bvalue}imageView.backgroundColor = UIColor(red: CGFloat(rvalue), green: CGFloat(gvalue), blue: CGFloat(bvalue), alpha: CGFloat(alphaSlider.value))if let gradientLayer = imageView.layer.sublayers?[0] as? CAGradientLayer{gradientLayer.colors = [UIColor.black.cgColor , UIColor(red: CGFloat(redSlider.value), green: CGFloat(greenSlider.value), blue: CGFloat(blueSlider.value), alpha: CGFloat(alphaSlider.value)).cgColor,UIColor.black.cgColor]}}
以上~謝謝大家
下面這是我的Github