SwiftUI 是一種非常簡單的創(chuàng)新方法,可以利用 Swift 的強大能力在所有蘋果設備平臺上構建用戶界面。通過 SwiftUI,開發(fā)者僅使用一組工具和 API 就能為所有蘋果設備構建用戶界面。SwiftUI 使用易于閱讀和編寫的聲明式 Swift 語法,可與新的 Xcode 設計工具無縫協(xié)作,使你的代碼和設計完美同步。SwiftUI 自動支持動態(tài)類型、黑暗模式、本地化和可訪問性,你的 SwiftUI 代碼將成為你寫過的最強大的 UI 代碼。
目標
快速了解SwfitUI。
成果:實現(xiàn)一個列表,點擊列表的item,跳轉(zhuǎn)到對應的詳情。
本文根據(jù)蘋果官方教程整理代碼在這里
首先回想一下在UIKit中如何實現(xiàn):
- 創(chuàng)建一個帶導航Navigation的controller,用來布局和Push下一個頁面。
- 添加UITableView,并實現(xiàn)UITableView的兩個代理方法,展示列表。
- 創(chuàng)建UITableViewCell,布局UILabel 和 UIImageView。
- 創(chuàng)建詳情頁面,布局地圖、三個UIlabel。
- 在UITableViewDelegate的代理方法中Push到詳情。
對iOS開發(fā)來說這太簡單太熟悉不過了,但很多代碼比較繁瑣,控件的創(chuàng)建、布局等。雖然簡單,但繁瑣,浪費了很多本該多花在業(yè)務上的時間。
在SwiftUI中怎么實現(xiàn)呢?
在實現(xiàn)之前,先看一下所需要的組件,按照用途大致分為基礎組件、布局組件和功能性組件,以及XCode11提供的新功能。
所需組件
基礎組件
Text
用來顯示文字 類似于UIKit中的UILabel
Image
用來顯示圖片 類似于UIKit中的UIImageView
Spacer
用來填充空白
布局組件
VStack
豎直擺放的組合組件HStack
水平擺放的組合組件List
用來展示列表 類似于UIKit中的UITableView
功能型組件
-
NavigationView
展示導航欄 類似于UINavigationBar
-
NavigationButton
類似于pushViewController:
方法
XCode11相關功能
預覽
實時看到對頁面的做出的修改
-
純SwiftUI時,默認靜態(tài)預覽。
點擊預覽串口的Resume按鈕。
如果沒有顯示預覽窗口則按下圖操作打開即可
- 預覽包含UIView子類視圖時,需要打開時時預覽
點擊可以切換時時預覽和靜態(tài)預覽
拖放
command鍵 + 鼠標點擊組件,可以方便的添加組件,設置組件屬性等。
代碼實現(xiàn)
創(chuàng)建列表
struct LandmarkList : View {
var body: some View {
//自定義顯示的內(nèi)容
List(0 ..< 5) { item in
Text("hello")
.font(.title)
}
}
}
使用List
組件可以快速的創(chuàng)建滑動列表,不需要設置代理,不需要實現(xiàn)協(xié)議方法就達到類似于UIKit中UITableView的效果。
Text
用來展示文字,通過.font
設置了字體大小。將它放入List
中,它就是列表的Item。
效果:
從工程Resources文件夾中找到資源文件,引入工程,里面包含了json數(shù)據(jù)、圖片等。再引入Models文件夾中的Data.swift
和Landmark.swift
,這些主要是為了組件數(shù)據(jù)和Model,不是本文討論的重點。下面會用到這些數(shù)據(jù)。
創(chuàng)建Item
這一步在UIKit中像自定義UITableViewCell,需要再其中添加一個圖片和一個文字。
在SwiftUI中,沒有UITableViewCell的概念,需要顯示一行的時候,只需要使用HStack
組件,HStack
組件是一個組合組件,其中可以放 Text
、Image
等組件。
創(chuàng)建 LandmarkRow
struct LandmarkRow : View {
var landmark: Landmark
var body: some View {
HStack {
landmark.image(forSize: 50)
Text(landmark.name)
}
}
}
landmark.image(forSize: 50)
這個方法返回一個指定大小的圖片
Text
顯示地標名稱。
HStack
將圖片和文字組合在一行里面顯示,并配置的有默認格式。
效果:
把它帶入第一步創(chuàng)建的列表中,并引入數(shù)據(jù)。
struct LandmarkList : View {
var body: some View {
List(landmarkData) { landmark in
LandmarkRow(landmark: landmark)
}
}
}
效果:
列表已經(jīng)顯示出來了。
想想UIKit中的那堆代碼,是不是暗爽?
創(chuàng)建詳情頁
從效果圖中看到詳情頁有一個地圖、一個圓形圖片、幾個顯示地名、位置的文字。
從布局上看最下面兩個水平的文字可以擺放在水平組件中,再和標題文字一起擺放在豎直組件中。
地圖、圖片、水平擺放的組件再一起擺放在豎直擺放組件中。
創(chuàng)建地圖模塊:
struct MapView : UIViewRepresentable {
var coordinate: CLLocationCoordinate2D
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ view: MKMapView, context: Context) {
let span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
let region = MKCoordinateRegion(center: coordinate, span: span)
view.setRegion(region, animated: true)
}
}
要在SwiftUI中添加非SwiftUI的組件,需要遵循UIViewRepresentable
協(xié)議,并實現(xiàn)協(xié)議方法。
創(chuàng)建圓角圖片:
struct CircleImage : View {
var image: Image
var body: some View {
image
.clipShape(Circle())
.overlay(
Circle().stroke(Color.white, lineWidth: 4)
.shadow(radius: 10)
)
}
}
創(chuàng)建詳情頁
struct LandMarkDetail : View {
var landmark : Landmark
var body: some View {
VStack {
MapView(coordinate: landmark.locationCoordinate).frame(height: 300)
CircleImage(image: landmark.image(forSize: 250))
.offset(y: -130)
.padding(.bottom, -130)
//三個文字
VStack(alignment: .leading) {
Text(landmark.name)
.font(.title)
//下面兩個文字
HStack {
Text(landmark.park)
.font(.subheadline)
Spacer()
Text(landmark.state)
.font(.subheadline)
}
}
.padding()
Spacer()
}
}
}
VStack
豎直組合組件,里面包含了MapView
和CircleImage
以及VStack
。
VStack
中包含了標題文字以及HStack
.
HStack
中包含了水平擺放的兩個文字組件。
效果:
實現(xiàn)跳轉(zhuǎn)
上面已經(jīng)分別實現(xiàn)了列表頁和詳情頁面,下面實現(xiàn)跳轉(zhuǎn)。
UIKit中想要Push效果需要創(chuàng)建UINavigationController ,想要顯示導航欄需要設置UINavigationBar,想要跳轉(zhuǎn)需要在UITableView的代理方法中調(diào)用pushViewController:
方法。
修改上面創(chuàng)建的列表:
struct LandmarkList : View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
NavigationButton(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
.navigationBarTitle(Text("Landmarks"), displayMode: .inline)
}
}
}
NavigationView
組件類似于UINavigationBar
,可以設置導航欄標題和模式。
NavigationButton
可以直接將跳轉(zhuǎn)方法直接和列表展示綁定在一起,邏輯更清晰明了。
總結(jié)
了解過Flutter的同學對這個接受可能會很快。
沒有了解過Flutter的同學需要轉(zhuǎn)變一下頁面布局思路。
SwiftUI對iOS開發(fā)同學來是一大福音,畢竟都9012年了,還在使用UIKit中這么原始的布局,實在是苦不堪言。
SwiftUI需要iOS13以上的系統(tǒng),但目前公司開發(fā)APP都會支持一定的老版本系統(tǒng),還得使用UIKit。全面使用SwiftUI預計還有一段時間。畢竟,還有很多公司沒有使用Swift呢。