實戰教程·什麼年代了還在敲傳統木魚?(二)
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(四)