實戰教程·元宇宙來了,準備好你的電子名片了嗎?(二)

語言: CN / TW / HK

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天后未獲授權禁止轉載,侵權必究!

「其他文章」