實戰程式設計·刻在男人DNA裡的浪漫,空氣投籃(二)
theme: smartblue
前提回顧
在上一章節中,我們完成了“準備遊戲”頁面和“遊戲列表”頁面,並完成了遊戲列表的簡單互動,在本章中,我們將繼續完成其他的相關內容。
實戰程式設計
頁面切換
在整個空氣投籃專案中,“準備遊戲”頁面和“遊戲列表”頁面的互動邏輯是,開啟App展示“準備遊戲”頁面,同時喚起Watch端的授權,授權通過後,進入到“遊戲列表”頁面。
當前Watch端先行忽略,我們先完成切換切換的邏輯。首先宣告一個變數儲存切換動作,如下程式碼所示:
@State var isAffirmInWatch: Bool = false
上述程式碼中,我們聲明瞭一個Bool型別的變數isAffirmInWatch
,初始狀態位false。
當isAffirmInWatch是否授權狀態為true時,我們進入到gameListView遊戲列表頁面,若沒有授權,則停留在prepareView準備遊戲頁面。如下程式碼所示:
if isAffirmInWatch {
gameListView()
} else {
prepareView()
.onTapGesture {
self.isAffirmInWatch = true
}
}
上述程式碼中,為了演示方便,我們給prepareView準備遊戲檢視加了一個onTapGesture點選事件,當點選prepareView準備遊戲檢視時,切換isAffirmInWatch是否授權狀態為true,如此在點選時便可進入到gameListView遊戲列表檢視。
遊戲回合檢視
接下來,當用戶點選遊戲列表的遊戲項時,需要進入到遊戲詳情頁。
而對於“投籃專案”來說,一般有3~5個回合,在正式遊戲開始之前,會展示一個類似“Round1,Ready Go”的遊戲回合頁面,然後才是正式遊戲詳情頁。
為此,我們需要建立一個新的SwiftUI頁面來承載它,在Xcode左側檢視工具欄中新建一個SwiftUI檔案,命名為GameDetailView
,如下圖所示:
在“遊戲回合”檢視中,我們可以看到幾個頁面元素:遊戲回合數(Round1)、遊戲規則(5米)、遊戲規則說明(距離籃筐)、遊戲結果(投中:0)。
由於上述的引數會隨著遊戲更新內容,因此需要宣告其變數進行儲存,如下程式碼所示:
@State var roundNum:Int = 1
@State var distanceNum:Int = 5
@State var gameGoal:Int = 0
上述程式碼中,我們聲明瞭3個變數:roundNum
遊戲回合數、distanceNum
籃筐距離、gameGoal
單回合遊戲得分。這裡由於在後續要使用到數值計算,因此宣告的變數都是Int
型別。
緊接著,我們來分析構建頁面,如下程式碼所示:
``` // 遊戲回合 func preStartView() -> some View { VStack { Spacer() VStack(alignment: .center, spacing: 40) { Text("Round" + String(roundNum)) .font(.system(size: 48, design: .rounded)) .bold() .foregroundColor(.white)
VStack(alignment: .center, spacing: 20) {
Text(String(distanceNum) + "米")
.font(.system(size: 24))
.foregroundColor(.white)
.bold()
Text("距離籃筐")
.font(.system(size: 17))
.foregroundColor(.white)
}
}
Spacer()
Spacer()
Text("投中: " + String(gameGoal))
.font(.system(size: 17))
.foregroundColor(.white)
}
} ```
上述程式碼中,我們建立了一個新的檢視preStartView
。
分析下頁面元素,Text回合數文字為主要文字,使用48號圓形字型樣式,並設定bold加粗,foregroundColor文字填充顏色為白色,其餘文字基本修飾符型別。
這裡科普一個知識點。
由於宣告的變數是Int型別,而Text文字需要鍵入String型別的文字,因此需要將Int型別轉換為String型別。SwiftUI對於型別轉換可以直接使用型別包裹進行轉換,示例:String(roundNum)
,如此便可以直接將roundNum遊戲回合數轉換為String型別的引數。
另外,我們可以使用“+”對字串進行拼接,組成一個新的字串,示例:
"I"+"Love"+"You" 結果為 "ILoveYou"
迴歸正題,文字部分也是使用VStack垂直佈局檢視進行包裹元素,這裡的程式設計思想是“由中間向兩邊散開”,即相距離較近的元素可以先組合成一個容器,再和外邊的容器進行組合,便於設定檢視元素之間的間距。
完成好單個preStartView檢視後,我們在Body中展示它,如下程式碼所示:
ZStack {
Color(.black).edgesIgnoringSafeArea(.all)
preStartView()
}
遊戲中檢視
在遊戲回合檢視展示後,使用者會進入到“遊戲中”檢視,正式開始參與遊戲。如下圖所示:
空氣投籃遊戲的遊戲檢視很簡答,還原在現實生活中的籃筐,由一個計分板和投籃的籃筐組成,而計分板分為兩塊,分別為個位數計分板和十位數計分板。
我們首先要匯入“籃筐”的圖片,同樣是在黑色背景下,我們需要一張SVG格式的向量圖,如下圖所示:
回到GameDetailView遊戲詳情頁,我們來構建遊戲中檢視的樣式,由於需要統計計分板的分數,因此需要宣告好變數部分,如下程式碼所示:
@State var unitsDigit: Int = 0
@State var tensDigit: Int = 0
上述程式碼中,unitsDigit
為計分板個位數,tensDigit
為計分板十位數。然後,我們再構建樣式部分,如下程式碼所示:
// 遊戲頁面
func playGameView() -> some View {
VStack(alignment: .center, spacing: 40) {
HStack(alignment: .center, spacing: 20) {
Text(String(unitsDigit))
.font(.system(size: 120))
.bold()
.foregroundColor(.white)
.padding(40)
.background(Color.gray)
.cornerRadius(8)
Text(String(tensDigit))
.font(.system(size: 120))
.bold()
.foregroundColor(.white)
.padding(40)
.background(Color.gray)
.cornerRadius(8)
}
Image("ball")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: UIScreen.main.bounds.size.width / 2)
}
}
上述程式碼,在playGameView
檢視中,我們使用HStack橫向佈局容器包裹了計分板的樣式內容。
關於Text文字背景部分,SwiftUI提供的方法是使用padding撐開距離,再使用background背景顏色填充撐開的間距,最後再使用cornerRadius設定圓角。
如此,便實現了計分板的樣式效果,圖片部分這裡就不多說了。
同樣,前期什麼的Int型別的引數,在Text文字元件中使用需要轉換成String字串型別,方可使用。
此時我們就完成了2個頁面:preStartView
遊戲回合檢視、playGameView
遊戲中檢視。這裡做頁面的切換,我們也可以宣告一個引數來進行狀態的切換,如下程式碼所示:
@State var isReady:Bool = false
然後通過宣告好的isReady
引數進行頁面間的切換,如下程式碼所示:
if isReady {
playGameView()
} else {
preStartView()
}
進入&返回
經過兩個章節的學習,我們完成了兩個主要的檢視:ContentView
首頁檢視、GameDetailView
遊戲詳情檢視,共4個頁面,接下來,我們要將這4個頁面串起來。
回到ContentView首頁檢視,我們盤一盤邏輯,在使用者點選遊戲項時,將會進入到GameDetailView遊戲詳情檢視,遊戲詳情頁首先會展示回合檢視,然後再開始遊戲。
瞭解了基本的互動邏輯後,我們先完成頁面之間的跳轉,這裡可以使用基於NavigationView頂部導航欄的跳轉方式,如下程式碼所示:
NavigationView {
ZStack {
Color(.black).edgesIgnoringSafeArea(.all)
if isAffirmInWatch {
gameListView()
} else {
prepareView()
.onTapGesture {
self.isAffirmInWatch = true
}
}
}
}
上述程式碼中,需要使用NavigationView
將整個檢視包裹起來,然後再在gameListView遊戲列表檢視中新增跳轉方法,如下程式碼所示:
NavigationLink(destination: GameDetailView()) {
gameRowView(gameName: "投籃", gameHelpText: "手舉球開始遊戲", gameImage: "basketball")
}
如此,當我們點選“投籃”的遊戲項時,就會跳轉到GameDetailView遊戲詳情頁。
我們來到GameDetailView遊戲詳情頁,由於當前GameDetailView遊戲詳情頁的isReady引數變數為false,因此GameDetailView遊戲詳情頁會展示preStartView遊戲回合檢視。
我們希望的互動是preStartView遊戲回合檢視在顯示2秒後自動到playGameView遊戲中檢視。
這裡在頁面載入時增加多一個方法,如下程式碼所示:
ZStack {
Color(.black).edgesIgnoringSafeArea(.all)
if isReady {
playGameView()
} else {
preStartView()
}
}
.onAppear(){
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.isReady = true
}
}
上述程式碼中,我們在GameDetailView遊戲詳情頁onAppear
展示時添加了一個在主執行緒上的操作,即基於當前時間2秒鐘後,切換isReady狀態。
如此,我們便實現了在使用者進入GameDetailView遊戲詳情頁時,先展示preStartView遊戲回合檢視,再展示preStartView遊戲中檢視了。
進入操作有了,最後是返回操作。
原有的返回按鈕太醜了,我們可以自定義一個返回按鈕,如下程式碼所示:
// 返回上一頁
func backButton() -> some View {
Button(action: {
}) {
Image(systemName: "chevron.left.circle")
.font(.system(size: 17))
.foregroundColor(.white)
}
}
並將它加到GameDetailView遊戲詳情頁檢視中,如下程式碼所示:
ZStack {
Color(.black).edgesIgnoringSafeArea(.all)
if isReady {
playGameView()
} else {
preStartView()
}
}
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: backButton())
返回的操作互動也很簡單,我們可以呼叫SwiftUI的通用返回方法,如下程式碼所示:
@Environment(.presentationMode) var mode
最後在點選backButton
返回按鈕的時候使用返回方法,如下程式碼所示:
self.mode.wrappedValue.dismiss()
本章預覽
完成後,我們回到ContentView預覽下整體專案。
本章小結
恭喜你,完成了本章的所有內容!
在本章中,我們構建了遊戲詳情頁的檢視,並完成了詳情頁的兩種狀態頁面,準備開始遊戲和遊戲中的狀態頁面,還實現了從首頁跳轉到詳情頁、返回首頁的全過程。
空氣投籃專案iOS端整體的互動內容基本就到這裡了,接下來我們將繼續使用MVVM開發模式調整iOS端的內容,後面還會完成Watch端的頁面及其互動。
最後如果條件成熟,我們將呼叫Apple提供的各種感測器來完成真實的互動體驗。
請保持期待吧~
版權宣告
本文為稀土掘金技術社群首發簽約文章,14天內禁止轉載,14天后未獲授權禁止轉載,侵權必究!
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(一)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(八)
- 實戰教程·什麼年代了還在敲傳統木魚?(二)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(七)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(六)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(五)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(四)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(三)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(二)
- 實戰教程·什麼年代了還在敲傳統木魚?(一)
- 技術下午茶:產品經理是如何工作的?如何才算一份好的需求文件?如何設計一個簡單的列表,它應該具備哪些基本功能?
- 釋出&選擇釋出,使用SwiftUI搭建一個新建釋出彈窗(上)
- 釋出&選擇釋出,使用SwiftUI搭建一個新建釋出彈窗(下)
- 使用SwiftUI搭建一個風箏搖擺動畫,實現放風箏的夢想~
- SwiftUI100天:使用SwiftUI搭建一個計時器App
- 實戰程式設計·使用SwiftUI從0到1完成一款iOS筆記App(三)
- 初識MVVM·關於啟動頁、引導頁、登入頁的設計細節和互動邏輯
- 誰說程式設計師不懂浪漫,教你使用SwiftUI搭建一個電子相簿送給她吧~
- 實戰程式設計·刻在男人DNA裡的浪漫,空氣投籃(二)
- 實戰程式設計·使用SwiftUI從0到1完成一款iOS筆記App(四)