作業#20 — 點餅乾遊戲(cookie clicker) App
Published in
19 min readApr 26, 2023
練習 IBOutlet, IBAction、設置 Segmented Control、設置點擊音效。
.作業來源:
Topics
I. 設置 Segmented Control
II. 設置按鈕
III. 設置音效
I. 設置 Segmented Control
- 型別:UISegmentedControl
- 常用 properties:
>selectedSegmentIndex
: 獲取或設置當前選中的選項索引。
>setTitle (_Name: String, forSegmentAt: Int)
: 設置指定索引處的標題。(* 這裡的名稱會覆蓋 main inspector 處的命名。)
>setImage (image: UIIMage, forSegmentAt: Int)
: 設置指定索引處的圖片。
>selectedSegmentTintColor
: 設置控件選中時的顏色。
>backgroundColor
: 控件背景顏色。 - 常用 methods:
>insertSegment (withTitle:String, at:Int, animated:Bool )
: 在指定位置插入一個新的選項。
>setEnabled ( Bool, forSegmentAt: Int )
: 設置指定索引處的選項是否可用。
// properties:
instrumentSegmentedControl.setTitle("木魚", forSegmentAt: 0)
instrumentSegmentedControl.setTitle("敲鐘", forSegmentAt: 1)
instrumentSegmentedControl.selectedSegmentTintColor = UIColor(red: 1, green: 0, blue: 0, alpha: 1)
instrumentSegmentedControl.backgroundColor = UIColor(red: 0, green: 0, blue: 1, alpha: 1)
//methods:
instrumentSegmentedControl.insertSegment(withTitle: "測試用", at: 1, animated: false )
instrumentSegmentedControl.setEnabled(false, forSegmentAt: 1)
II. 設置按鈕
- 型別:UIButton
- 常用 properties:
>tintColor
: 設置按鈕顏色。
>backgroundColor
: 設置背景宴色。
>layer.borderWidth
: 設置邊框寬度。
>layer.borderColor
: 設置邊框顏色。
>titleLabel
: UIButton 中的 UILabel,可通過它設置文字顯示樣式,例如字體、顏色、對齊方式等。
>imageView
: UIButton 中的 UIImageView,可通過它設置圖片顯示樣式,例如顯示模式、圖片內容填充方式等。 - 常用 methods:
>setTitle (String, for: status)
: 設置按鈕的顯示文字。常用 status 為 .normal 跟 .highlighted。
>setTitleColor (UIColor, for: status)
: 設置按鈕文字顏色。
*留意若想透過程式碼設置設置文字顏色(setTitleColor
),則一定要使先用程式碼來設置文字以及狀態(setTitle
)!
>setImage (UIimage, for: status)
: 設置按鈕的圖片和狀態。也可以設置為 SF symbols,若要調整 symbols 尺寸可見下方範例。
>sizeToFit()
: 根據按鈕的內容調整按鈕的大小。
>setEnabled (Bool, animated: Bool)
: 設置按鈕是否可用,可選擇是否帶動畫
//properties
resetButton.tintColor = UIColor.lightGray
resetButton.backgroundColor = UIColor.red
resetButton.setTitleColor(UIColor.lightGray, for: .highlighted)
//methods
resetButton.setTitle("完成", for: .normal)
resetButton.setTitleColor(UIColor.black, for: .normal)
// *setImage 設置成 symbol Image 並調整 symbol 大小範例:
let symbolConfiguration = UIImage.SymbolConfiguration(scale: .small)
myButton.setImage(UIImage(systemName: "arrow.uturn.backward", withConfiguration: symbolConfiguration), for: .normal)
*所謂的 “常用” properties 及 methods 只是我個人覺得自己比較可能會使用到的,沒有一定標準~
III. 設置音效
//需先導入多媒體設置工具集
import AVFoundation
//在使用 AVAudioPlayer 播放音頻時,我們需要創建一個 AVAudioPlayer instance。
class ViewController: UIViewController {
var myAudioPlayer: AVAudioPlayer?
override func viewDidLoad() {
super.viewDidLoad()
/*
所有的應用程式資源文件 (例如圖片、音頻文件等) 都包含在應用程式的 Bundle 中。
Bundle.main 表示應用程式的主 Bundle,也就是包含所有應用程式資源的 Bundle。可以使用 Bundle.main.url(forResource:withExtension:) 方法來獲取應用程式 Bundle 中指定資源的 URL。
*/
//"myAudioFile" 是指要獲取的音頻文件的文件名 (不包含擴展名)。"mp3" 是指音頻文件的擴展名。
let myUrl = Bundle.main.url(forResource: "myAudioFile", withExtension: "mp3")!
/*
do { try } catch {} 是 Swift 中用來處理錯誤的結構,通常稱為錯誤處理機制。
在 do 區塊中,我們可以使用 try 關鍵字來調用可能會引發錯誤的函數、方法或操作。如果這些操作沒有出現錯誤,程式就會繼續往下執行。
如果出現錯誤,就會自動跳轉到 catch 區塊中,進行錯誤處理。
*/
do {
myAudioPlayer = try AVAudioPlayer(contentsOf: myUrl)
//這裡可以順便調整音量(如果需要的話)
myAudioPlayer?.volume = 0.8
} catch {
print("播放音效檔案出現錯誤:\(error)")
}
}
// IBAction 連結按鈕功能。當按下按鈕時,會開始播放音頻,而且每次按下按鈕都會從頭開始播放。
@IBAction func clickToPlayAudioButton (_ sender: Any) {
//啟動播放音頻
myAudioPlayer?.play()
//停止播放音頻
myAudioPlayer?.stop()
//音頻播放器的當前時間,以秒為單位。可以使用這個屬性來設置播放位置或查詢當前的播放位置。
myAudioPlayer?.currentTime = 0
myAudioPlayer?.play()
}
}
}
*要留意把音頻導入專案中時,不要加到 Assets 裡面、而是直接拉到跟 Assets/ Main 同一個列就好! 我在設置時誤把音頻夾到 Assets 裡,導致一直出現 錯誤”Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value”🥲
Steps
- Segmented Control
//segmented control IBOutlet 連結到 View Controller (建議放在 viewDidLoad 前)
@IBOutlet weak var instrumentSegmentedControl: UISegmentedControl!
@IBOutlet weak var instrumentImageView: UIImageView!
//segmented control IBAction 連結到 View Controller(建議放在 viewDidLoad 後)
@IBAction func instrumentPageChange(_ sender: Any) {
// 設置 segmented control 可切換的頁面常數
let instrumentPage = instrumentSegmentedControl.selectedSegmentIndex
// 設置在某頁數時,顯示的項目
if instrumentPage == 0 {
instrumentImageView.image = UIImage(named: "muyu")
knockTimes.text = ("敲擊次數:\(muyuCount)")
} else if instrumentPage == 1 { instrumentImageView.image = UIImage(named: "bell")
knockTimes.text = ("敲擊次數:\(bellCount)")
}
}
*如果只把畫面設置在 segmented control 下,要是沒有點擊切換過 segmented control 頁面,則 Page 0 的內容很可能無法正確顯示。故也要將 page 0 的內容放到 viewDidLoad 內,使其可以在初始畫面載入後直接顯示並運作。
override func viewDidLoad() {
super.viewDidLoad()
//最初始的畫面設定
instrumentImageView.image = UIImage(named: "muyu")
knockTimes.text = ("敲擊次數:\(muyuCount)")
audioPlayerMuyu?.play()
audioPlayerMuyu?.stop()
audioPlayerMuyu?.currentTime = 0
audioPlayerMuyu?.play()
}
2. 設置按鈕
//設置點擊按鈕計數
var muyuCount = 0
var bellCount = 0
//敲擊次數Label、圖片上的隱形按鈕、結束按鈕先 IBOutlet 連結到 View Controller (建議將連結到 viewDidLoad 前)
@IBOutlet weak var instrumentClick: UIButton!
@IBOutlet weak var knockTimes: UILabel!
@IBOutlet weak var resetButton: UIButton!
...
//圖片上的隱形按鈕 IBAction 連結到 View Controller(建議放在 viewDidLoad 後)
@IBAction func knockOnInstrument(_ sender: Any) {
if instrumentImageView.image == UIImage(named: "muyu") {
muyuCount += 1
knockTimes.text = ("敲擊次數:\(muyuCount)")
} else if instrumentImageView.image == UIImage(named: "bell") {
bellCount += 1
print(bellCount)
knockTimes.text = ("敲擊次數:\(bellCount)")
}
}
//結束按鈕 IBAction 連結到 View Controller(建議放在 viewDidLoad 後)
@IBAction func reset(_ sender: Any) {
if instrumentImageView.image == UIImage(named: "muyu") {
muyuCount = 0
knockTimes.text = ("敲擊次數:\(muyuCount)")
} else if instrumentImageView.image == UIImage(named: "bell") {
bellCount = 0
print(bellCount)
knockTimes.text = ("敲擊次數:\(bellCount)")
}
}
3. 設置音效
//先導入音頻和視頻的處理框架
import AVFoundation
//設置接下來會使用到的兩種音效播放器
var audioPlayerMuyu: AVAudioPlayer?
var audioPlayerBell: AVAudioPlayer?
//在 viewDidLoad 中進行播放設置
override func viewDidLoad() {
super.viewDidLoad()
let muyuUrl = Bundle.main.url(forResource: "muyuSound", withExtension: "mp3")!
do {
audioPlayerMuyu = try AVAudioPlayer(contentsOf: muyuUrl)
} catch {
print("播放音效檔案出現錯誤:\(error)")
}
let bellUrl = Bundle.main.url(forResource: "bellSound", withExtension: "mp3")!
do {
audioPlayerBell = try AVAudioPlayer(contentsOf: bellUrl)
audioPlayerBell?.volume = 0.8
} catch {
print("播放音效檔案出現錯誤:\(error)")
}
}
//在圖片點擊案牛中加入播放 method
@IBAction func knockOnInstrument(_ sender: Any) {
if instrumentImageView.image == UIImage(named: "muyu") {
muyuCount += 1
knockTimes.text = ("敲擊次數:\(muyuCount)")
audioPlayerMuyu?.play()
audioPlayerMuyu?.stop()
audioPlayerMuyu?.currentTime = 0
audioPlayerMuyu?.play()
} else if instrumentImageView.image == UIImage(named: "bell") {
bellCount += 1
print(bellCount)
knockTimes.text = ("敲擊次數:\(bellCount)")
audioPlayerBell?.play()
audioPlayerBell?.stop()
audioPlayerBell?.currentTime = 0
audioPlayerBell?.play()
}
}
4. 設置 Launch Screen
直接在 LaunchScreen 裡加入圖片即可。只是很想把這句話放進 App 🤣
操作影片
完整程式碼:
//
// ViewController.swift
// Clicker & Segmented Control
//
// Created by 陳佩琪 on 2023/4/26.
//
import UIKit
import AVFoundation
class ViewController: UIViewController {
var audioPlayerMuyu: AVAudioPlayer?
var audioPlayerBell: AVAudioPlayer?
var muyuCount = 0
var bellCount = 0
// 木魚 & 鐘圖片
@IBOutlet weak var instrumentImageView: UIImageView!
// segmented Control
@IBOutlet weak var instrumentSegmentedControl: UISegmentedControl!
// 圖片上的隱形按鈕
@IBOutlet weak var instrumentClick: UIButton!
// 敲擊次數顯示
@IBOutlet weak var knockTimes: UILabel!
// 結束按鈕
@IBOutlet weak var resetButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let muyuUrl = Bundle.main.url(forResource: "muyuSound", withExtension: "mp3")!
do {
audioPlayerMuyu = try AVAudioPlayer(contentsOf: muyuUrl)
} catch {
print("播放音效檔案出現錯誤:\(error)")
}
let bellUrl = Bundle.main.url(forResource: "bellSound", withExtension: "mp3")!
do {
audioPlayerBell = try AVAudioPlayer(contentsOf: bellUrl)
audioPlayerBell?.volume = 0.8
} catch {
print("播放音效檔案出現錯誤:\(error)")
}
//最初始的畫面設定
instrumentImageView.image = UIImage(named: "muyu")
knockTimes.text = ("敲擊次數:\(muyuCount)")
audioPlayerMuyu?.play()
audioPlayerMuyu?.stop()
audioPlayerMuyu?.currentTime = 0
audioPlayerMuyu?.play()
}
// segmented control 頁面切換
@IBAction func instrumentPageChange(_ sender: Any) {
let instrumentPage = instrumentSegmentedControl.selectedSegmentIndex
if instrumentPage == 0 {
instrumentImageView.image = UIImage(named: "muyu")
knockTimes.text = ("敲擊次數:\(muyuCount)")
} else if instrumentPage == 1 { instrumentImageView.image = UIImage(named: "bell")
knockTimes.text = ("敲擊次數:\(bellCount)")
}
}
// 點擊圖片按鈕
@IBAction func knockOnInstrument(_ sender: Any) {
if instrumentImageView.image == UIImage(named: "muyu") {
muyuCount += 1
knockTimes.text = ("敲擊次數:\(muyuCount)")
audioPlayerMuyu?.play()
audioPlayerMuyu?.stop()
audioPlayerMuyu?.currentTime = 0
audioPlayerMuyu?.play()
} else if instrumentImageView.image == UIImage(named: "bell") {
bellCount += 1
print(bellCount)
knockTimes.text = ("敲擊次數:\(bellCount)")
audioPlayerBell?.play()
audioPlayerBell?.stop()
audioPlayerBell?.currentTime = 0
audioPlayerBell?.play()
}
}
// 結束按鈕
@IBAction func reset(_ sender: Any) {
if instrumentImageView.image == UIImage(named: "muyu") {
muyuCount = 0
knockTimes.text = ("敲擊次數:\(muyuCount)")
} else if instrumentImageView.image == UIImage(named: "bell") {
bellCount = 0
print(bellCount)
knockTimes.text = ("敲擊次數:\(bellCount)")
}
}
}