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

語言: CN / TW / HK

theme: smartblue

前提回顧

在上兩個章節中,我們完成了個人主頁以及添加身份卡頁面的設計,其中學習如何數據模型、列表創建卡片展示視圖,以及打開頁面和關閉頁面的交互動作,在本章節中,我們來學習搭建添加身份卡頁面的相關內容。

界面分析:頁面元素及其優先級

添加身份卡頁面,需要根據個人主頁身份卡的內容來構建,身份卡對應展示的信息,就是我們需要在新增時創建的信息,如下圖所示:

對於信息的優先級,主要信息為平台稱號,其次信息是平台圖標和平台名稱,再次隱藏信息是鏈接地址。

確定頁面元素的優先級需要遵循用户慣性邏輯以及應用想給用户呈現的關鍵點,在身份卡中對於用户而言最核心的信息是在平台所取得的稱號,而平台稱號也是在個人主頁身份卡中用户視線首要關注的內容。

其次的平台信息部分,由平台圖標和平台名稱組成,這是由於這兩塊信息具有相關性,平台名稱對應着平台圖標,因此在產品設計上可以耦合在一起。

最後是鏈接地址部分,後續我們希望關聯對應平台地址後,能點擊身份卡片在應用內打開瀏覽器並訪問鏈接地址,而鏈接地址在整個身份卡片中是不展示其內容的,因此信息的優先級可以放置至最後。

變量聲明:身份卡必要參數準備

分析完界面元素後,我們在創建頁面之前先確定好需要使用到的變量,如下代碼所示:

@State var platformIcon: String = "icon_juejin" @State var title: String = "移動端簽約作者" @State var platformName: String = "稀土掘金技術社區" @State var indexURL: String = "http://juejin.cn/user/3897092103223517"

上述代碼中,我們都使用@State進行變量的聲明,@State可以存儲聲明的變量及其變量的值。並且為了呈現效果,我們給聲明的參數都賦予了初始值。

界面設計:平台稱號輸入框

聲明好需要的變量後,我們來搭建平台稱號輸入框內容,我們可以和搭建closeBtn關閉按鈕視圖一樣,單獨搭建平台輸入框視圖,再將該視圖內容賦予NewView主要的視圖中,如下代碼所示:

// 頭銜名稱輸入框 func titleInputView() -> some View { TextField("請輸入頭銜", text: $title) .padding() .background(Color(.systemGray6)) .cornerRadius(8) .padding(.horizontal) }

上述代碼中,我們創建了一個平台稱號輸入框視圖titleInputView,主體內容使用TextField輸入框控件,輸入框提示文字為“請輸入頭銜”,輸入內容綁定聲明的變量title。

在樣式方面,為了突出輸入框視圖內容,使用padding修飾符“撐開”輸入框外層區域,將外層區域填充背景色為systemGray6,並設置圓角度數為8,最後設置水平位置兩邊留白,便實現了上圖效果。

界面設計:自定義平台選擇器

接下來我們來設計“選擇平台”的操作邏輯。可以簡單設想下,用户在“添加身份卡”頁面輸入完平台稱號後,下一步是選擇該稱號所在的社區或者平台。

最直觀的展現方式是將平台都排列出來讓用户進行選擇,而由於展示空間有限,我們可以只展示平台的圖標。當用户看到平台圖標時,通過點擊選擇以確定平台,而且平台選擇單張身份卡只能選擇一個平台。

有了基礎的想法後,我們來實現這個交互邏輯。

首先需要創建一個平台展示的數據集合,我們聲明一個數據用於存放數據,如下代碼所示:

private let platforms = [ ("稀土掘金技術社區", "icon_juejin"), ("CSDN博客", "icon_csdn"), ("阿里雲社區", "icon_aliyun"), ("華為雲社區", "icon_huaweiyun"), ]

上述代碼中,我們聲明瞭一個常量數組platforms,在platforms數組內有兩個內容,前一個參數是平台名稱,後一個參數是平台圖標。

聲明好數據後,我們來創建平台選擇樣式部分,這次需要用到的SwiftUI控件是LazyVGrid垂直網格佈局容器,LazyVGrid垂直網格佈局容器類似VStack垂直佈局容器,不同的是VStack垂直佈局容器只能將內部的元素垂直排布,而LazyVGrid垂直網格視圖容器可以保持垂直佈局的情況下,將內部的元素分為幾列,如下圖所示:

LazyVGrid垂直網格佈局容器使用需要提前聲明網格的列數,如下代碼所示:

private var gridItemLayout = [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]

上述代碼中,我們聲明瞭佈局容器的GridItem列項為4列自適應調整的列項,將參數賦予變量值gridItemLayout。

緊接着我們來使用LazyVGrid垂直網格佈局容器,LazyVGrid垂直網格佈局容器的使用方法和List列表的使用方法類似,通過與ForEach循環遍歷配合使用,我們依舊使用單獨構建視圖的方法創建它,如下代碼所示:

// 平台選擇器 func platformPicker() -> some View { LazyVGrid(columns: gridItemLayout, spacing: 10) { ForEach(0 ..< platforms.count, id: .self) { item in Image(platforms[item].1) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 48, height: 48) .clipShape(Circle()) } } }

上述代碼中,我們創建了“選擇平台”視圖platformPicker,在platformPicker視圖中使用LazyVGrid垂直網格佈局容器搭建網格視圖,LazyVGrid的columns列項為上面聲明的gridItemLayout,網格之間元素的spacing間距為10。

和List列表的方法一樣,我們使用ForEach循環遍歷platforms數組的數據,並使用了Image圖片控件來展示platforms數組中的數據。由於platforms數組使用兩個數據,因此我們使用下標法指向數組的第二個數據(計算機數據從0開始計數)。

在這裏還需要考慮一個問題,當我們平台圖標太多時,可能會佔據整個App的頁面,我們可以在LazyVGrid垂直網格佈局容器最外層增加一個ScrollView滾動視圖容器,並設置滾動視圖的高度,如此LazyVGrid垂直網格佈局容器不管有多少元素,都只會在ScrollView滾動視圖容器中展示,如下代碼所示:

ScrollView { LazyVGrid(columns: gridItemLayout, spacing: 10) { ForEach(0 ..< platforms.count, id: .self) { item in Image(platforms[item].1) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 48, height: 48) .clipShape(Circle()) } } } .padding() .background(Color(.systemGray6)) .cornerRadius(8) .padding(.horizontal) .frame(maxHeight: 180)

很好,完成了“平台選擇器”的樣式之後,我們來實現交互邏輯部分,首先我們要看到用户點擊選擇的平台是哪一個,並將其凸顯出來。

由於ForEach是遍歷數據給到了item,因此當用户點擊了指定的item時,該item對應的樣式與其他未選中的樣式分隔開。為了實現這個效果,我們首先要聲明一個變量,知道選中的是哪一個item,如下代碼所示:

@State var selectedItem = 0

當選中時,即item的值等於selectedItem時,我們設置圖片加一層邊框,如果不是,則保持原樣,如下代碼所示:

if item == selectedItem { Image(platforms[item].1) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 48, height: 48) .clipShape(Circle()) .overlay( Circle() .stroke(Color.green, lineWidth: 4) ) } else { Image(platforms[item].1) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 48, height: 48) .clipShape(Circle()) .onTapGesture { selectedItem = item } }

上述代碼中,我們通過判斷當前的item是否等於selectedItem來構建不同的圖片樣式,如果一致,則Image圖片使用overlay修飾符覆蓋一層綠色的圓形邊框。如果不一致,則保持原來的樣式,在原有的樣式上增加onTapGesture點擊事件,當點擊的時候,讓selectedItem選中的item等於點擊的item。

可以在模擬器上試試效果,如下圖所示:

另外,當點擊平台圖標時,我們需要給聲明的變量進行賦值,如下代碼所示:

platformIcon = platforms[item].1 platformName = platforms[item].0

如此,便完成了“自定義平台選擇器”的所有內容。

界面設計:鏈接地址多行文本框

接下來我們來完成鏈接地址的交互設計,TextEditor多行文本框控件和TextField輸入框控件的使用方法類似,不同的是至今TextEditor多行文本框控件都沒有提供placeholder提示文字的設置方法,只能由開發者自行實現。

不過沒關係,實現多行文本框的方法及其提示文字的方法也很簡單,如下代碼所示:

``` // 鏈接地址 func indexURLView() -> some View { ZStack(alignment: .topLeading) { TextEditor(text: $indexURL) .font(.system(size: 17)) .padding(15)

    if indexURL.isEmpty {
        Text("請輸入主頁鏈接")
            .foregroundColor(Color(UIColor.placeholderText))
            .padding(20)
    }
}
.background(Color(.systemGray6))
.cornerRadius(8)
.padding()
.frame(maxHeight: 240)

} ```

上述代碼中,我們創建了一個多行文本框視圖indexURLView作為鏈接地址的輸入框,在indexURLView視圖中使用ZStack堆棧視圖建立層級關係,當TextEditor輸入框的綁定的內容indexURL為空時,則展示一個Text文本作為提示文字。

如此就實現了TextEditor多行文本框及其提示文字的交互。

交互設計:添加身份卡按鈕及其方法

完成添加身份卡的頁面元素後,我們來實現將輸入的內容添加到“個人主頁”的方法。

首先我們先創建基本的按鈕,如下代碼所示:

// 添加按鈕 func addBtn() -> some View { Button(action: { }) { Text("添加") .font(.system(size: 17)) .foregroundColor(.white) .bold() .padding() .frame(maxWidth: .infinity) .background(Color.green) .cornerRadius(8) .padding(.horizontal) } }

回到NewView的Body部分,所有元素我們均以搭建完成,所有視圖的排布我們可以使用VStack垂直佈局容器進行排布,如下代碼所示:

``` VStack(spacing: 15) { titleInputView()

platformPicker()

indexURLView()

addBtn()

Spacer()

} ```

樣式完成之後,我們來實現添加身份卡到個人主頁的交互。

我們來到Model.swift數據模型文件,原來我們聲明瞭models數組變量,我們需要將其剪切到ContentView文件中來,作為ContentView中的一部份,用於後面的數據雙向綁定使用,如下圖所示:

然後回到NewView文件中,聲明用於雙向綁定的數據模型,如下代碼所示:

@Binding var models: [Model]

由於使用了@Binding進行雙向綁定參數,因此NewView中不能存在private聲明的變量,因此我們需要刪除原來platforms數組和gridItemLayout網格佈局的private,並且給NewView賦予默認值,如下代碼所示:

NewView(models: .constant([]))

還需要回到ContentView文件,對使用NewView視圖中聲明的雙向綁定的models進行綁定,如下圖所示:

最後我們還需要回到NewView視圖中,實現添加身份卡的方法,如下代碼所示:

let newItem = Model(platformIcon: platformIcon, title: title, platformName: platformName, indexURL: indexURL) models.append(newItem)

上述代碼中,我們在點擊addBtn添加按鈕時,實現添加身份卡的方法,首先先聲明一個常量newItem存放符合Model數據模型的數據,並將數據模型的對應的值填充為我們在NewView聲明的變量(由於採用一樣的命名,因此就有了上面的效果),然後調用append的方法將符合數據模型的數據添加到models數組中。

此時我們就可以刪除NewView中聲明的變量的默認值,讓用户自定定義填充,如下代碼所示:

@State var title: String = "" @State var indexURL: String = ""

同時我們也可以刪除在ContentView中models數組的默認值,讓我們自己操作創建數據,如下代碼所示:

@State var models:[Model] = []

整體預覽

接下來,讓我們在模擬器中操作電子名片App的全路徑,如下圖所示:

iShot_2022-11-13_17.19.38.gif

本章小結

在本章中,我們學習瞭如何搭建“添加身份卡”頁面,包含輸入框基礎控件的使用,多行文本框基礎控件的使用。

本章的核心內容是自定義選擇器的創建,我們使用ScrollView滾動視圖容器、LazyVGrid垂直網格容器搭建了選擇器,並實現了單選的功能。最後我們通過雙向綁定視圖數組數據的方式,實現了添加身份卡到個人主頁的方法。

在本章的例子中,其實可以運用到其他App案例中,最常見的示例:todo待辦事項和note筆記。

下面的章節中,我們來繼續學習點擊身份卡片在App打開瀏覽器並訪問鏈接地址的功能及其他相關操作,請保持期待吧~

版權聲明

本文為稀土掘金技術社區首發簽約文章,14天內禁止轉載,14天后未獲授權禁止轉載,侵權必究!

「其他文章」