實戰教程·元宇宙來了,準備好你的電子名片了嗎?(二)
theme: smartblue
前提回顧
在上一章中,我們創建了CardView構件,使用了構件編程方式搭建視圖。使用構件的好處是當我們要整體修改構件內容時,就可以只修改構件的結構體,而無需每個卡片視圖都修改。
示例,在上一章中我們設置了平台圖標圖片,但由於平台圖標樣式的不統一性,看起來有些不協調。這時候,我們可以給CardView構件中的Image控件設置為圓形,讓其更加美觀些,如下圖所示:
對於搭建好的構件,只需要修改CardView構件本身,就可以在引用此構件的所有地方統一修改其樣式。
是不是很方便?接下來讓我們繼續完成下面的內容。
結構化編程:搭建數據模型
使用構件創建身份卡片視圖後,我們發現如果每次要新增一個卡片,就需要在卡片視圖中需要複製CardView構件並賦值。當我們需要創建很多身份卡片時,就會需要很多一樣的代碼,這不夠優雅。
有沒有辦法像搭建CardView構件一樣,只搭建一個結構然後填充數據,讓結構自動“遍歷”出內容?
SwiftUI聲明式語言中,可以使用List列表組件循環遍歷內容,在此之前我們需要定義好數據模型。我們創建一個新的Swift文件,命名為Model,如下圖所示:
Model文件作為我們搭建數據模型的文件,定義數據需要聲明的變量。首先我們引用SwiftUI,如下代碼所示:
import SwiftUI
接下來搭建數據模型,如下代碼所示:
struct Model: Identifiable {
var id = UUID()
var platformIcon: String
var title: String
var platformName: String
var indexURL: String
}
數據模型可以使用Class類或者Struct結構體聲明,這裏我們使用Struct結構體聲明瞭一個數據模型Model,遵循Identifiable協議。“Identifiable可識別”協議可以通過id區分不同的數據,當我們創建的數據中有兩條一模一樣的數據時,由於“Identifiable可識別”協議,系統將賦予不同的id,實現呈現兩條數據內容的效果。
使用Identifiable協議除了聲明需要的參數變量外,還需要在數據模型中聲明一個id,並複製為UUID。該數據模型中的需要使用的變量參數,我們可以直接使用之前在CardView身份卡片構件聲明的參數。
聲明好參數後,我們為展示數據,可以創建一個數據數組作為示例數據,如下代碼所示:
``` // MARK: 示例數據
var models = [ Model(platformIcon: "icon_juejin", title: "移動端簽約作者", platformName: "稀土掘金技術社區", indexURL: "https://juejin.cn/user/3897092103223517"), Model(platformIcon: "icon_csdn", title: "iOS創作者", platformName: "CSDN博客", indexURL: ""), Model(platformIcon: "icon_aliyun", title: "專家博主", platformName: "阿里雲社區", indexURL: ""), Model(platformIcon: "icon_huaweiyun", title: "專家博主", platformName: "華為雲社區", indexURL: ""), ] ```
如此便完成了數據模型的搭建。
卡片視圖:List列表和ForEach循環
我們回到ContentView視圖中,刪除原有的身份卡片視圖的代碼。卡片視圖我們可以看作一個列表,每張身份卡片就是一行行呈現的數據,列表的數據源則來源於上述創建好的數組models,如下圖所示:
List {
ForEach(models) { item in
CardView(platformIcon: item.platformIcon, title: item.title, platformName: item.platformName, indexURL: item.indexURL)
}
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
}
上述代碼中,我們使用List列表和ForEach循環結構,遍歷models數組中定義好的數據內容,並在調用CardView身份卡片構件的時候賦值為循環後item的一條條數據。
由於演示的iPhonex模擬器,因此為了呈現更好的列表樣式效果,使用listRowBackground列表項背景修飾符,將列表背景顏色修飾為透明。並使用listRowSeparator列表分割線修飾符,隱藏List自帶的分割線。完成這些操作後後,就可以完成展示身份卡片構件的樣式內容。
在模擬器中預覽的效果中,身份卡片左右邊距太寬了,我們可以直接修改CardView構件的代碼,去掉最後的padding邊距,如下圖所示:
導航菜單:標題和新建卡片入口
卡片視圖完善之後,我們來搭建頂部導航菜單。SwiftUI提供了NavigationView導航視圖控件方便我們快速搭建應用的頂部導航菜單。從視圖層級來看,頂部導航菜單是“包裹”整個頁面視圖的,因此NavigationView導航視圖控件需要在ContentView的body視圖最外層,如下代碼所示:
NavigationStack {
//視圖內容
.navigationBarTitle("文如秋雨",displayMode: .inline)
}
在iOS16版本,使用NavigationStack導航視圖控件搭建頂部導航菜單,iOS16版本以下的機型使用NavigationView導航。
搭建好頂部導航欄後,我們創建一個新的按鈕,作為創建身份卡片的入口。可以使用navigationBarItems導航欄按鈕修飾符創建導航菜單上的按鈕入口,不過在此之前,我們需要搭建好按鈕的視圖,再將按鈕賦予navigationBarItems導航欄按鈕修飾符。如下代碼所示:
``` func addBtn() -> some View { Button(action: {
}) {
Image(systemName: "plus.circle.fill")
.font(.system(size: 17))
.foregroundColor(.blue)
}
}
```
上述代碼中,我們完成了一個按鈕視圖addBtn。一般在編程過程中,若視圖中除樣式代碼外還有交互操作,通常會將其抽離出來作為一個單獨的視圖進行構建,然後再在修飾符或者其他視圖中使用,這是SwiftUI開發中經常會遇到的事情。
完成按鈕視圖的構建後,我們將按鈕視圖加到頂部導航菜單中,如下代碼所示:
.navigationBarItems(trailing: addBtn())
模態彈窗:打開一個新頁面
個人主頁部分基本已經完成了,下面我們來完成點擊頂部導航菜單的“添加”按鈕,打開“新建身份卡”頁面。
首先我們先創建一個新的SwiftUI文件,命名為NewView,如下圖所示:
回到ContentView視圖中,使用Sheet模態彈窗控件,創建打開彈窗的樣式,如下代碼所示:
.sheet(isPresented:Is Presented) {
Content
}
上述代碼中,我們使用sheet修飾符控件搭建打開模態彈窗效果,但需要使用sheet修飾符控件,需要提前聲明好觸發打開動作的變量,如下代碼所示:
@State var showNewView:Bool = false
並將聲明好的觸發變量綁定到sheet修飾符控件中,以及設置Content跳轉的頁面目標為NewView。如下代碼所示:
.sheet(isPresented: $showNewView) {
NewView()
}
最後在點擊addBtn按鈕視圖時,切換showNewView打開視圖的變量狀態,便可實現點擊“添加按鈕”打開模態彈窗,如下代碼所示:
self.showNewView.toggle()
關閉彈窗的方法也很類似,我們來到NewView視圖,給NewView視圖的內容添加頂部導航菜單,並也創建一個關閉彈窗的按鈕,如下代碼所示:
``` struct NewView: View { var body: some View { NavigationStack { Text("Hello, World!") .navigationBarTitle("添加身份卡", displayMode: .inline) .navigationBarItems(trailing: closeBtn()) } }
func closeBtn() -> some View {
Button(action: {
}) {
Image(systemName: "xmark.circle.fill")
.font(.system(size: 17))
.foregroundColor(.gray)
}
}
} ```
上述代碼中,我們使用的方法和個人主頁的內容基本一致,使用NavigationStack導航菜單控件創建導航菜單,並使用navigationBarTitle頂部導航標題控件創建標題。單獨創建關閉按鈕視圖closeBtn,並將它賦予導航菜單中的navigationBarItems導航菜單欄目修飾符,以創建導航菜單上的按鈕。
關閉彈窗:雙向綁定或全局變量
實現打開模態彈窗後,我們來實現關閉模態彈窗,下面我們來介紹兩種關閉模態彈窗的方法:雙向綁定、全局變量。
由於我們在ContentView個人主頁聲明瞭一個變量showNewView來打開模態彈窗,當點擊addBtn按鈕時更新其狀態。因此我們也可以在NewView頁面中也聲明一個雙向綁定的變量showNewView,並在點擊closeBtn時更新其狀態,實現關閉彈窗的交互。
首先先聲明一個雙向綁定的變量showNewView如下圖所示:
@Binding var showNewView:Bool
然後在點擊closeBtn關閉按鈕時更新其狀態,如下代碼所示:
self.showNewView.toggle()
由於使用@Binding聲明變量,因此在NewView視圖中聲明的變量缺少賦值,將可能導致無法預覽,因此我們在預覽時需要給NewView視圖賦予默認值,如下代碼所示:
NewView(showNewView: .constant(false))
建立雙向綁定的視圖,在所有頁面也都需要進行@Binding聲明變量的綁定,因此我們回到ContentView視圖中,綁定showNewView變量,如下代碼所示:
NewView(showNewView: $showNewView)
完成後,可以在模擬器中操作打開模態彈窗和關閉模態彈窗的交互。
另一種關閉模態彈窗的方法是聲明一個全局變量,實現關閉彈窗的效果,如下代碼所示:
``` //聲明環境變量 @Environment(.presentationMode) var presentationMode
//調用 self.presentationMode.wrappedValue.dismiss() ```
上述代碼中,我們聲明瞭一個全局變量presentationMode,在點擊closeBtn關閉按鈕的時候調用presentationMode全局變量的wrappedValue.dismiss方法實現關閉彈窗效果。
兩種方式在實際開發過程中均有使用,除模態彈窗外,在頁面之間使用入棧出棧的方式進行切換頁面也經常會用到。
在模態彈窗交互邏輯中更經常使用全局變量關閉彈窗的方式,無需進行雙向綁定已經給視圖添加默認值,也就無需示例在其他頁面缺少綁定參數的麻煩。
本章小結
在本章中,我們主要實現了使用數據模型和List列表來構建身份卡片視圖的內容,在減少代碼量的同時,其實也是為了之後對身份卡片進行新增、編輯、刪除做前期準備。
在SwiftUI中,複雜的具有相似結構的界面設計,通常會使用List列表和ForEach來實現,常見的類似Todo待辦事項App中的卡片列表、信息流App的信息列表、短視頻平台的視頻封面卡片視圖等等。
另外我們還學習了使用NavigationStack導航菜單控件(iOS16版本及以上機型使用,低於此版本機型使用NavigationView,Apple經常會在新控件完善後棄用舊控件,這點有點煩)及其標題、導航按鈕修飾符的使用,並進一步瞭解了使用sheet模態彈窗修飾符打開彈窗。關閉彈窗部分,我們介紹了兩種方式實現關閉彈窗,並簡單介紹了其使用特點。
在下面的章節中,我們將繼續完成“添加身份卡”頁面的相關操作,請保持期待吧~
版權聲明
本文為稀土掘金技術社區首發簽約文章,14天內禁止轉載,14天后未獲授權禁止轉載,侵權必究!
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(一)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(八)
- 實戰教程·什麼年代了還在敲傳統木魚?(二)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(七)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(六)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(五)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(四)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(三)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(二)
- 實戰教程·什麼年代了還在敲傳統木魚?(一)
- 技術下午茶:產品經理是如何工作的?如何才算一份好的需求文檔?如何設計一個簡單的列表,它應該具備哪些基本功能?
- 發佈&選擇發佈,使用SwiftUI搭建一個新建發佈彈窗(上)
- 發佈&選擇發佈,使用SwiftUI搭建一個新建發佈彈窗(下)
- 使用SwiftUI搭建一個風箏搖擺動畫,實現放風箏的夢想~
- SwiftUI100天:使用SwiftUI搭建一個計時器App
- 實戰編程·使用SwiftUI從0到1完成一款iOS筆記App(三)
- 初識MVVM·關於啟動頁、引導頁、登錄頁的設計細節和交互邏輯
- 誰説程序員不懂浪漫,教你使用SwiftUI搭建一個電子相冊送給她吧~
- 實戰編程·刻在男人DNA裏的浪漫,空氣投籃(二)
- 實戰編程·使用SwiftUI從0到1完成一款iOS筆記App(四)