實戰教程·什麼年代了還在敲傳統木魚?(二)
theme: smartblue
前提回顧
在上一章節中,我們完成了“電子木魚”專案的基礎部分,包含基礎的UI樣式、互動邏輯和動畫效果。這一章節,我們來實現“電子木魚”App的聲音播放、自定義設定頁面及其互動邏輯。
音訊準備:木魚敲擊聲
當每次點選木魚的時候,電子木魚App都需要發出“咚”的敲擊聲。我們在網上可以找到並下載木魚敲擊聲,下載好的檔案拖入到專案中,如下圖所示:
在此請記住下載的音訊的時長(通常為1秒),以及檔名稱、檔案字尾名(通常為mp3、m4a),在之後的程式碼中需準確呼叫。
緊接著,我們來實現音訊播放相關的程式碼。音訊播放需要使用到一個新的框架:AVFoundation。
AVFoundation是蘋果在iOS和OS X系統中,用於處理基於時間的媒體資料的Objective-C框架,供使用者來開發媒體型別的應用程式。
AVFoundation框架可以用來實現播放聲音的效果,首先需要在專案中引入AVFoundation框架,由於是Apple自帶的框架,可以直接在專案中import匯入,如下程式碼所示:
import AVFoundation
為了專案方便,我們可以建立一個新的Swift檔案來放置播放音訊的相關程式碼。建立一個新的Swift檔案,命名為AudioPlayer。在AudioPlayer檔案中,引入AVFoundation框架,預設一個播放器,然後建立一個方法來使用播放器,如下程式碼所示:
``` import AVFoundation import Foundation import SwiftUI
var soundPlayer: AVAudioPlayer?
func playAudio(forResource: String, ofType: String) { let path = Bundle.main.path(forResource: forResource, ofType: ofType)! let url = URL(fileURLWithPath: path)
do {
soundPlayer = try AVAudioPlayer(contentsOf: url)
soundPlayer?.play()
} catch {
print("音訊檔案出現問題")
}
} ```
上述程式碼中,我們預先建立了一個播放器soundPlayer,然後建立了一個方法playAudio播放聲音,傳入兩個引數,forResource用於確定所需播放的音訊檔案的檔名稱,ofType為檔案的字尾名。
確定後引數後,將兩個引數值給到路徑path,再把路徑給到地址url,便於後面播放器使用。在程式碼中使用聲音播放器AVAudioPlayer播放聲音,如果嘗試執行失敗則列印輸出錯誤資訊。
完成後,回到Content檔案,在點選木魚時呼叫playAudio方法,如下程式碼所示:
playAudio(forResource: "dong", ofType: "mp3")
在預覽視窗敲擊了一下,效果不錯(不禁笑出了聲)。
頁面跳轉:開啟設定頁面
接下來,我們再升級一下,嘗試編輯“功德值”引數等相關內容。我們建立一個新的SwiftUI檔案,命名為DetailView,如下圖所示:
回到ContentView檔案,我們先來實現頁面跳轉互動邏輯。從ContentView跳轉到DetailView頁面的互動,是通過導航檢視右邊的按鈕進行跳轉,按鈕部分可以使用navigationBarItems導航欄元素修飾符建立,如下程式碼所示:
.navigationBarItems(trailing: Image(systemName: "slider.horizontal.3"))
如此我們建立了按鈕的樣式部分,但設定按鈕不能進行互動,若是我們在建立按鈕,並且實現按鈕的互動動作,那麼在navigationBarItems導航欄元素修飾符中的程式碼就太過於複雜,且不夠清晰。
我們可以建立按鈕元素檢視,將再這個檢視賦予navigationBarItems導航欄元素修飾符,以減少在修飾符中存在太多的不同性質的程式碼,如下程式碼所示:
``` func settingBtn() -> some View { Button(action: {
}) {
Image(systemName: "slider.horizontal.3")
.foregroundColor(.white)
}
} ```
頁面跳轉部分,需要提前宣告一個Bool型別的引數來控制跳轉動作,如下程式碼所示:
@State var showDetailView:Bool = false
頁面跳轉可以使用Sheet模態彈窗開啟方式,在Library選擇Modifiers修飾符欄目,找到sheet的修飾符,拖到VStack縱向佈局容器中,並繫結宣告好的觸發條件及確定好需要開啟的頁面,如下程式碼所示:
.sheet(isPresented: $showDetailView) {
DetailView()
}
建立好頁面跳轉方法後,將觸發條件給予到點選按鈕處,並在點選設定按鈕時,切換showDetailView的狀態,如下程式碼所示:
self.showDetailView.toggle()
在預覽視窗點選頂部導航選單的“設定”按鈕,即可開啟DetailView頁面。
設定頁面:自定義內容
來到DetailView頁面,先設想下我們需要設定的內容,整個電子木魚App可以設定哪些內容?
聯想在ContentView頁面使用@State宣告的變數,兩個頁面引數需要進行聯動,則在DetailView頁面需要使用@Bingding宣告相同的變數,用於兩個頁面的資料繫結,如下程式碼所示:
@Binding var gameType: String
@Binding var totalNumber: Int
@Binding var number: Int
使用@Binding做資料雙向繫結需要注意2點,一是在DetailView頁面宣告的用於繫結的變數缺少預設值,因此在檢視預覽的時候需要給予預設值方可正常預覽,如下程式碼所示:
DetailView(gameType: .constant(""), totalNumber: .constant(0), number: .constant(0))
二是在DetailView頁面宣告的變數,若其他頁面需要跳轉到該頁面,則需要繫結DetailView頁面宣告的值。
我們在ContentView頁面需要跳轉到DetailView頁面,因此回到ContentView頁面,在跳轉的地方繫結對應的引數值,如下程式碼所示:
DetailView(gameType: $gameType, totalNumber: $totalNumber, number: $number)
完成後,專案不再提示報錯資訊後,我們回到DetailView頁面來完善頁面相關內容。
樣式部分,可以使用Form表單作為主體框架,在Library選擇Views欄目,找到Form表單控制元件,拖入到主體檢視中,如下圖所示:
引數設定部分,虔誠內容可以使用輸入框作為設定,在Library選擇Views欄目,找到TextField輸入框控制元件,拖入到Form表單中,輸入框內容繫結使用@Bingding繫結的gameType引數,如下程式碼所示:
TextField("請輸入內容", text: $gameType)
初始總量部分,我們可以使用步進器作為設定數值的控制元件,在Library選擇Views欄目,找到Stepper步進器控制元件,拖入到Form表單中,Stepper步進器的值繫結初始總量totalNumber。
文字部分為了更好地展示該項設定的內容,可以使用欄位拼接內容,同理,每次敲擊木魚增加的數值也可以使用Stepper步進器,如下程式碼所示:
Form {
TextField("請輸入內容", text: $gameType)
Stepper(value: $totalNumber, in: 0...9999) {
Text(gameType + ":" + "(totalNumber)")
}
Stepper(value: $number, in: 1...9999) {
Text(gameType + " + " + "(number)")
}
}
由於在DetailView頁面並沒有傳入相應的值,因此在預覽視窗只能看到缺少值的效果,我們在ContentView頁面中點開設定檢視繫結引數值後的效果,如下圖所示:
很好,我們嘗試除錯了下專案,運轉不錯。
最後,我們還需要增加關閉彈窗的互動動作,和上面提及過的方法一致,我們可以建立按鈕元素檢視,將再這個檢視賦予navigationBarItems導航欄元素修飾符,作為收起彈窗的按鈕,如下程式碼所示:
``` func closeBtn() -> some View { Button(action: {
}) {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.white)
}
} ```
然後對整個表單外層增加一個NavigationStack導航欄,並給Form表單增加navigationBarItems修飾符,建立關閉按鈕的樣式,順便再把標題加上如下程式碼所示:
.navigationBarTitle("編輯內容", displayMode: .inline)
.navigationBarItems(trailing: closeBtn())
完成之後,建立一個環境變數用於實現關閉彈窗互動,並在點選關閉按鈕時呼叫它,如下程式碼所示:
``` //宣告環境變數 @Environment(.presentationMode) var presentationMode
//呼叫 self.presentationMode.wrappedValue.dismiss() ```
如此就完成了關閉彈窗的互動效果,回到ContentView檢視試試效果,如下圖所示:
專案預覽:整體專案效果展示
完成之後,我們回到ContentView頁面,預覽下整體效果,如下圖所示:
專案總結
在本次專案中,我們通過“電子木魚”專案學習瞭如何使用SwiftUI這一宣告式建立頁面元素,也接觸了完全使用Library通過拖拽元件和修飾符的方式來構建頁面。
動畫和互動方面,首次使用了AVFoundation框架,結合SwiftUI實現了敲擊木魚的“咚咚咚”音訊播放,在執行專案聽到“咚”的那一刻,也都忍不住想笑出聲,總算能體會到為何“電子木魚”App能夠火起來的原因。
如果一款軟體為人們帶來快樂,即使它沒有特別的功能,也不失為一款優秀的作品。
版權宣告
本文為稀土掘金技術社群首發簽約文章,14天內禁止轉載,14天后未獲授權禁止轉載,侵權必究!
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(一)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(八)
- 實戰教程·什麼年代了還在敲傳統木魚?(二)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(七)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(六)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(五)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(四)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(三)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(二)
- 實戰教程·什麼年代了還在敲傳統木魚?(一)
- 技術下午茶:產品經理是如何工作的?如何才算一份好的需求文件?如何設計一個簡單的列表,它應該具備哪些基本功能?
- 釋出&選擇釋出,使用SwiftUI搭建一個新建釋出彈窗(上)
- 釋出&選擇釋出,使用SwiftUI搭建一個新建釋出彈窗(下)
- 使用SwiftUI搭建一個風箏搖擺動畫,實現放風箏的夢想~
- SwiftUI100天:使用SwiftUI搭建一個計時器App
- 實戰程式設計·使用SwiftUI從0到1完成一款iOS筆記App(三)
- 初識MVVM·關於啟動頁、引導頁、登入頁的設計細節和互動邏輯
- 誰說程式設計師不懂浪漫,教你使用SwiftUI搭建一個電子相簿送給她吧~
- 實戰程式設計·刻在男人DNA裡的浪漫,空氣投籃(二)
- 實戰程式設計·使用SwiftUI從0到1完成一款iOS筆記App(四)