用SwiftUI寫一個簡單頁面

QiShare發表於2019-11-18

級別:★★☆☆☆
標籤:「iOS 13」「SwiftUI」「Xcode 11.1」
作者: 647
審校: QiShare團隊


用SwiftUI寫一個簡單頁面

前言: 之前同事WYongW寫了一篇《用Flutter寫一個簡單頁面》,本篇將和大家一起調研一下蘋果今年推出的SwiftUI框架。 接下來,讓我們一起入門一下SwiftUI(嚐嚐鮮)。


一、SwiftUI是什麼?

1. 定義:

簡單來說,SwiftUI是蘋果在 “WWDC-2019” 推出的一款全新的 “宣告式UI” 框架。 拆開看,Swift + UI。(由此可以看出Swift越來越重要)

2. 特點:
  • “簡潔迅速”的Swift:越來越簡潔的Swift語法,配上Swift迅速的優勢。

  • “即視”的UI:降低除錯成本,一邊寫code、一邊就可檢視UI

  • 跨平臺:一套程式碼,即可完成iOSiPadOSmacOSwatchOS的開發與適配。

用SwiftUI寫一個簡單頁面

  • “宣告式”程式設計

簡單來說,對比之前的 “指令式”程式設計,我們通常需要告訴計算機**“怎麼做”? 而“宣告式”程式設計**是讓我們告訴計算機 “做什麼”?(至於最底層怎麼做,我們無需關心。)

舉個例子,對於寫UI而言,

  • 指令式程式設計:就是,怎麼畫? 把每個framelayout等等統統需要計算到位。
  • 宣告式程式設計:就是,畫什麼? 把想要的效果描述出來,其他都交給框架去做。
3. 開發環境:

這麼新的技術肯定需要環境的支援。SwiftUI所需要的開發環境,如下:

  • Xcode:Xcode 11.1+
  • MacOS:MacOS 10.15+
  • iOS:iOS 13+

PS:由於SwiftUI只能應用與iOS 13系統以上的裝置。 因此,這項技術不建議用在需要適配低版本(iOS 13 以下)的App上。 不過如果是無需適配低版本的新專案,或者學習者全可以上手“玩一玩”。 畢竟蘋果的新技術還是很有意思的嘛~

二、SwiftUI的基本元件(語法)

這塊知識比較“基礎”且“重要”。只有記住了這些基本元件,我們才能用較少的程式碼開發出精美的App。

下面,我將給大家介紹一些重要的SwiftUI元件:

元件介紹:

名稱 含義
Text 用來顯示文字的元件,類似UIKit中的UILabel
Image 用來展示圖片的元件,類似UIKit中的UIImageView
Button 用於可點選的按鈕元件,類似UIKit中的UIButton
List 用來展示列表的元件,類似UIKit中的UITableView
ScrollView 用來支援滑動的元件,類似UIKit中的UIScrollView
Spacer 一個靈活的空間,用來填充空白的元件。
Divider 一條分割線,用來劃分割槽域的元件。
VStack 將子檢視按**“豎直方向”**排列布局。(Vertical stack
HStack 將子檢視按**“水平方向”**排列布局。(Horizontal stack
ZStack 將子檢視按**“兩軸方向均對齊”**佈局(居中,有重疊效果)

基本元件:

  • Text:用來顯示文字的元件,類似UIKit中的UILabel
Text("Hello, we are QiShare!").foregroundColor(.blue).font(.system(size: 32.0))
複製程式碼
  • Image:用來展示圖片的元件,類似UIKit中的UIImageView
Image.init(systemName: "star.fill").foregroundColor(.yellow)
複製程式碼
  • Button:用於可點選的按鈕元件,類似UIKit中的UIButton
Button(action: { self.showingProfile.toggle() }) {
    Image(systemName: "paperplane.fill")
        .imageScale(.large)
        .accessibility(label: Text("Right"))
        .padding()
}
複製程式碼
  • List:用來展示列表的元件,類似UIKit中的UITableView
List(0..<5){_ in
        NavigationLink.init(destination: VStack(alignment:.center){
            Image.init(systemName: "\(item+1).square.fill").foregroundColor(.green)
            Text("詳情介面\(item + 1)").font(.system(size: 16))
    }) {
          //ListRow
       }
複製程式碼
  • ScrollView:用來支援滑動的元件,類似UIKit中的UIScrollView

  • Spacer:一個靈活的空間,用來填充空白的元件。

  • Divider:一條分割線,用來劃分割槽域的元件。

佈局元件:

  • VStack:將子檢視按**“豎直方向”**佈局。(Vertical stack)

  • HStack:將子檢視按**“水平方向”**佈局。(Horizontal stack)

  • ZStack:將子檢視按**“兩軸方向均對齊”**佈局。

功能元件:

  • NavigationView:負責App中導航功能的元件,類似UIKit中的UINavigationView

  • NavigationLink:負責App頁面跳轉的元件,類似於UINavigationView中的pushpop功能。

NavigationView {
    List(0..<5){_ in
        NavigationLink.init(destination: VStack(alignment:.center){
            Image.init(systemName: "\(item+1).square.fill").foregroundColor(.green)
            Text("詳情介面\(item + 1)").font(.system(size: 16))
    }) {
          //ListRow
       }
}
.navigationBarTitle("導航\(item)",displayMode: .inline)
複製程式碼
  • TabView:負責App中的標籤頁功能的元件,類似UIKit中的UITabBarController
TabView {
    Text("The First Tab")
        .tabItem {
            Image(systemName: "1.square.fill")
            Text("First")
        }
    Text("Another Tab")
        .tabItem {
            Image(systemName: "2.square.fill")
            Text("Second")
        }
    Text("The Last Tab")
        .tabItem {
            Image(systemName: "3.square.fill")
            Text("Third")
        }
}
.font(.headline)
複製程式碼

三、SwiftUI快速上手實踐

下面讓我們快速實現一個有TabView、NavigationView、List的Demo。

用SwiftUI寫一個簡單頁面

SF Symbols 是從 iOS 13macOS 10.15 開始內建於系統中的字元圖示庫,它提供了上千種常見的線條圖示,而且我們可以任意地為它們設定尺寸,顏色等屬性。Apple 甚至準備了專門的app:SF Symbols 來幫助你檢視可用的符號:

接下來就讓我們用這些Symbols製作個小Demo。

  • ContentView:
import SwiftUI

struct ContentView: View {
    
    @State var isLeftNav = false
    @State var isRightNav = false
    
    init() {
        //修改導航欄文字顏色
        UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: UIColor.systemBlue]
        UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.systemBlue]
        UINavigationBar.appearance().tintColor = .systemBlue
    }
    
    var body: some View {
        TabView {
            
            // Tab1:
            NavigationView {
                List(Symbols, id:\.self) {
                    ListRow(symbol: $0)
                }
                .navigationBarTitle(Text("SF Symbols"))
                .navigationBarItems(leading: leftNavButton, trailing: rightNavButton)
            }.tabItem {
                Image.init(systemName: "star.fill")
                Text("Tab1").font(.subheadline)
            }
            
            // Tab2:
            NavigationView {
                Text("This is the second tab.")
            }.tabItem {
                Image.init(systemName: "star.fill")
                Text("Tab2").font(.subheadline)
            }
        }
    }
    
    var leftNavButton: some View {
        Button(action: { self.isLeftNav.toggle() }) {
            Image(systemName: "person.crop.circle")
                .imageScale(.large)
                .accessibility(label: Text("Left"))
                .padding()
        }
        .sheet(isPresented: $isLeftNav) {
            VStack {
                Text("Hello, we are QiShare!").foregroundColor(.blue).font(.system(size: 32.0))

                HStack {
                    Spacer()
                    Spacer()
                    Text("an iOS Team. ").fontWeight(.black).foregroundColor(.purple)
                    Spacer()
                    Text("We are learning SwiftUI.").foregroundColor(.blue)
                    Spacer()
                }
            }
        }
    }
    
    var rightNavButton: some View {
        Button(action: { self.isRightNav.toggle() }) {
            Image(systemName: "paperplane.fill")
                .imageScale(.large)
                .accessibility(label: Text("Right"))
                .padding()
        }
        .sheet(isPresented: $isRightNav, onDismiss: {
            print("dissmiss RrightNav")
        }) {
            ZStack {
                Text("This is the Right Navi Button.")
            }
        }
    }
}
複製程式碼
  • ListRow:List對應的Cell
struct ListRow: View {
    var symbol: String
    var body: some View {
        NavigationLink(destination: ListDetail(symbol: symbol)) {
            
            HStack {
                //圖片
                Image(systemName: symbol)
                    .resizable()
                    .frame(width: 60, height: 60)
                    .foregroundColor(Colors.randomElement())
                //分割
                Divider()
                Spacer()
                //文字
                Text(symbol)
                Spacer()
            }
        }
    }
}
複製程式碼
  • ListDetail:
import SwiftUI

struct ListDetail: View {
    
    var symbol: String
    
    var body: some View {
        VStack {
            
            Text("Image:").font(.headline)
            
            Spacer()
            
            Image(systemName: symbol)
                .foregroundColor(Colors.randomElement())
                .imageScale(.large)
                .scaleEffect(3)
                .padding(.bottom, 100)
            
            Divider()
            
            Text("Image Name:").font(.headline)
            Spacer()
            Text(symbol)
                .font(.largeTitle)
            Spacer()
        }
        .navigationBarTitle(symbol)
    }
}
複製程式碼

原始碼:本文Demo


瞭解更多iOS及相關新技術,請關注我們的公眾號:

用SwiftUI寫一個簡單頁面

小編微信:可加並拉入《QiShare技術交流群》。

用SwiftUI寫一個簡單頁面

關注我們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公眾號)

推薦文章:
iOS 控制日誌的開關
iOS App中可拆卸一個framework的兩種方式
自定義WKWebView顯示內容(一)
Swift 5.1 (6) - 函式
Swift 5.1 (5) - 控制流
Xcode11 新建工程中的SceneDelegate
iOS App啟動優化(二)—— 使用“Time Profiler”工具監控App的啟動耗時
iOS App啟動優化(一)—— 瞭解App的啟動流程
奇舞週刊

相關文章