#15 Random亂數練習|除了手動,我們也可以交給命運來安排。
這次要挑戰的作業是下面這個👇主題決定蹭一下聯名的熱潮😆
聯名的商業模式除了在大街小巷穿梭以外(五桐號和Dinotaeng的聯名好可愛😍),最近幾年精品界也愛上這種A+B蹦出新滋味的玩法,Nike X Dior、Gucci X 哆啦A夢還有今年初的Louis Vuitton X 草間彌生,聯名風潮看來還會吹很~久。
這次的作業想讓Dior和Louis Vuitton做一次假聯名😛,來玩客製化包包遊戲!
📍作業目標:
👉使用Slider修改畫面上指定物件的顏色
👉使用亂數功能隨機產生顏色
👉使用Switch來控制畫面動畫
✨先上作品!👀
1.先將素材匯入Assets,並將Storyboard的元件都拉好。這邊要注意SliderLabel的文字框要能裝得下最大值255,可以先設255確認數字不會超出去,不然就會像下面這樣產生悲劇。
2.判斷畫面上的元件哪些要拉Action與Outlet,先思考物件之間的控制關係。
・圖片:顏色被Slider改變
・Label:數字被Slider改變
・Slider:獲得使用者的數值+控制Label與圖片
・Switch:獲得使用者是否開/關按鈕+控制星星出現
・Button:產生亂數改變Slider數值進而改變圖片顏色
3.開始寫程式~仔細看發現底部的LV Pattern與包包的角度不合,所以要先旋轉ImageView。先將LV Pattern的圖片拉一個Outlet,才能在程式碼裡面命令他工作,然後再將之前學過的旋轉ImageView程式碼加進去。
//此行寫在viewDidLoad fuction內,因為希望圖便在一打開畫面時就要旋轉完畢
let oneDegree = CGFloat.pi / 180
louisVuittonImageView.transform = CGAffineTransform.identity.rotated(by: oneDegree * -30)
4.Slider設定。拉動slider時,會有兩個動作:圖片改顏色以及slider label數字改變。
💡Tips1:像Slider這樣的元件,可以同時拉Action和Outlet。(做動和回饋都是同一個元件)
💡Tips2:如果不同元件都是一樣的Action,可以只拉一次就好。
4–1:設定圖片與Slider之間的關係。因為我們要改的是LV的背景,所以是設定backgroundColor去存入顏色資料。
//這邊寫在@IBAction func changeColor內
//因為RGB的值最多為1,所以要/255
louisVuittonImageView.backgroundColor = UIColor(red: CGFloat(redSlider.value/255), green: CGFloat(greenSlider.value/255), blue:CGFloat(blueSlider.value/255), alpha: 1)
4–2:設定Label與Slider之間的關係。在設定時,發現SliderLabel會是浮點數的方式呈現,這是因為value的型別是Float,所以要顯辦法把它轉換為整數,這邊列出三種不同的寫法,都可以達到同樣的效果。
//這邊寫在@IBAction func changeColor內
//Slider後的數字設定
redLabel.text = String(Int(redSlider.value))
greenLabel.text = Int(greenSlider.value).description
blueLabel.text = String(format:"%.0f", blueSlider.value)
//"%.0f"是要取到小數點後幾位的寫法,這邊寫取到第0位代表整數
🚨Storyboard上的Attributes Inspector Value預設值只有針對Slider物件本身,Label並不會改變,所以我們要自行為Label加入預設值。
//此行寫在viewDidLoad fuction內,因為希望畫面一開啟就是顯示255
redLabel.text = "255"
greenLabel.text = "255"
blueLabel.text = "255"
5.亂數Random Button設定,寫在亂數按鈕的Action裡。
//設定亂數,因為這個按鈕是一次產生3個針對Slider的亂數,所以3個slider都寫在此Func內
redSlider.value = Float.random(in: 0...255)
greenSlider.value = Float.random(in: 0...255)
blueSlider.value = Float.random(in: 0...255)
因為剛剛changeColor的功能是寫在別的IBAction Function裡,所以當亂數按鈕的Function也需要一樣功能時並不能直接呼叫(會連Function內的其他功能一起呼叫),要再寫一次(複製貼上就好啦~)。
//複製剛剛寫好的changeColor程式碼
//Image
louisVuittonImageView.backgroundColor = UIColor(red: CGFloat(redSlider.value/255), green: CGFloat(greenSlider.value/255), blue: CGFloat(blueSlider.value/255), alpha: 1)
//Slider
redLabel.text = String(Int(redSlider.value))
greenLabel.text = Int(greenSlider.value).description
blueLabel.text = String(format:"%.0f", blueSlider.value)
6.最後是參考同學作品,想要練習Switch的功能,所以我加入了星星動畫✨順便複習之前學到頭很痛的動畫設定😂
💡Tips1:因為在開啟畫面與Switch控制時都需要這個功能,所以將動畫做成Function,之後要使用再呼叫Function即可。
💡Tips2:做動畫的時候會有兩個常數:發射器細胞(Cell)與圖層(Layer),要將Layer寫在Function外,寫在Function內的話,每一次呼叫Function都會新增一個Layer,到時候只能唱星星堆滿天~
//常數會寫在Class裡面、所有Function外面
let starLayer = CAEmitterLayer()
func starEmitter(){
//設定星星動畫
let starEmitterCell = CAEmitterCell()
starEmitterCell.contents = UIImage(named: "star")?.cgImage
starEmitterCell.birthRate = 0.5
starEmitterCell.lifetime = 100
starEmitterCell.velocity = 1
starEmitterCell.yAcceleration = 1
starEmitterCell.scale = 0.3
starEmitterCell.spin = 0.5
starEmitterCell.emissionRange = .pi*0.5
//將 let starLayer = CAEmitterLayer()寫在func外
starLayer.emitterCells = [starEmitterCell]
starLayer.emitterPosition = CGPoint(x: view.bounds.width/2, y: -50)
starLayer.emitterSize = CGSize(width: view.bounds.width, height: 0)
starLayer.emitterShape = .line
view.layer.addSublayer(starLayer)
}
7.Switch設定,因為只有開和關兩種模式,所以可以用if-else去寫。讓星星消失其實只是把圖層從Superlayer中移除,但動畫在程式中還在跑,仔細看Gif會發現關掉再開啟後星星還是延續關掉前的樣子,只是往下移動了一點。
@IBAction func starSwitch(_ sender: Any) {
if starEmitterControl.isOn{
starEmitter()
} else {
starLayer.removeFromSuperlayer()
}
}
8.美化一下介面細節就完成啦!🥹
9.上傳GitHub
📍完整程式碼
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var louisVuittonImageView: UIImageView!
@IBOutlet weak var redSlider: UISlider!
@IBOutlet weak var greenSlider: UISlider!
@IBOutlet weak var blueSlider: UISlider!
@IBOutlet weak var redLabel: UILabel!
@IBOutlet weak var greenLabel: UILabel!
@IBOutlet weak var blueLabel: UILabel!
@IBOutlet weak var starEmitterControl: UISwitch!
let starLayer = CAEmitterLayer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//旋轉LV的圖片
let oneDegree = CGFloat.pi / 180
louisVuittonImageView.transform = CGAffineTransform.identity.rotated(by: oneDegree * -30)
//設定SliderLabel的預設值
redLabel.text = "255"
greenLabel.text = "255"
blueLabel.text = "255"
//一開畫面就有星星
starEmitter()
}
@IBAction func changeColor(_ sender: Any) {
//三個slider功能是一樣的,可以拉到同一個Action,就不用寫三個Action的內容
//拉動slider時,會有兩個動作,圖片改顏色以及slider label數字改變
//因為RGB的值最多為1,所以要/255
louisVuittonImageView.backgroundColor = UIColor(red: CGFloat(redSlider.value/255), green: CGFloat(greenSlider.value/255), blue: CGFloat(blueSlider.value/255), alpha: 1)
//Slider後的數字設定
redLabel.text = String(Int(redSlider.value))
greenLabel.text = Int(greenSlider.value).description
blueLabel.text = String(format:"%.0f", blueSlider.value)
//"%.0f"是要取到小數點後幾位的寫法,這邊寫取到第0位代表整數
}
@IBAction func random(_ sender: Any) {
//設定亂數,因為這個按鈕是一次產生3個針對Slider的亂數,所以3個slider都寫在此Func內
redSlider.value = Float.random(in: 0...255)
greenSlider.value = Float.random(in: 0...255)
blueSlider.value = Float.random(in: 0...255)
//複製剛剛寫好的changeColor程式碼
//Image
louisVuittonImageView.backgroundColor = UIColor(red: CGFloat(redSlider.value/255), green: CGFloat(greenSlider.value/255), blue: CGFloat(blueSlider.value/255), alpha: 1)
//Slider
redLabel.text = String(Int(redSlider.value))
greenLabel.text = Int(greenSlider.value).description
blueLabel.text = String(format:"%.0f", blueSlider.value)
}
func starEmitter(){
//設定星星動畫
let starEmitterCell = CAEmitterCell()
starEmitterCell.contents = UIImage(named: "star")?.cgImage
starEmitterCell.birthRate = 0.5
starEmitterCell.lifetime = 100
starEmitterCell.velocity = 1
starEmitterCell.yAcceleration = 1
starEmitterCell.scale = 0.3
starEmitterCell.spin = 0.5
starEmitterCell.emissionRange = .pi*0.5
//將 let starLayer = CAEmitterLayer()寫在func外
starLayer.emitterCells = [starEmitterCell]
starLayer.emitterPosition = CGPoint(x: view.bounds.width/2, y: -50)
starLayer.emitterSize = CGSize(width: view.bounds.width, height: 0)
starLayer.emitterShape = .line
view.layer.addSublayer(starLayer)
}
@IBAction func starSwitch(_ sender: Any) {
if starEmitterControl.isOn{
starEmitter()
} else {
starLayer.removeFromSuperlayer()
}
}
}
💡參考的作品