實戰編程·刻在男人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(四)