SwiftUI入門
標簽: iOS編程
摘要
這篇分享的內容是關于SwiftUI的一些知識,主要分為以下幾個方面:SwiftUI的概念和用法;WWDC 20大會上對swiftUI的更新介紹;SwiftUI在開發應用中的優缺點分析以及它和我們目前開發中使用的UIKit的比較;SwiftUI的發展前景等。
前景
從以下數據可以看出,未來swift將是iOS開發的唯一選擇,越早進行相關的遷移工作會對未來公司的發展越有利:
- 從 WWDC17 后 蘋果已經不再使用 Objective-C 做 Sample Code 演示
- https://developer.apple.com/不再更新Objective-C 相關的文檔
- WidgetKit 是 SwiftUI only
- App Clips 10M的包大小, SwiftUI 是最合適的框架
- 開源社區逐步放棄 Objecive-C 如 Lottie
SwiftUI介紹
SwiftUI是Apple在WWDC19上提出來的一個基于Swift編程語言,Xcode編譯器的聲明式的布局引擎,具有良好的跨平臺特性,可以為所有Apple平臺上的應用編寫界面,并且支持同步預覽,可視化編輯等功能。
基礎概念
swiftUI控件
Text:展示靜態文本內容的控件
Image:展示圖片的控件
HStack,VStack,Zstack:用來進行控件的不同排列,包括水平,垂直和subviews
struct ContentView: View {
var body: some View {
VStack {
Image("chilkoottrail")
.frame(width: 300, height: 300, alignment: .center)
.clipShape(Circle())
.overlay(
Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 10)
Text("chilkoottrail")
.font(.title)
}
}
}
List:list是swiftUI中的一個列表容器,實現的效果類似于UITableView,為我們提供一個可以滾動顯示數據的表格。
NavigationView:為我們的界面頂部提供一個導航視圖,被navigationView包裹起來的組件都會處于一個視圖棧中,可以進行頁面的push和pop切換,一般會有三個控件和navigationView結合使用:
- navigationLink:可以將一個新的視圖推進視圖棧中,跳轉的目標界面需要用到navigationLink來設置。功能類似于pushViewController
struct ContentView: View { var body: some View { NavigationView { NavigationLink(destination: Detail()) { Text("haha") } .navigationBarTitle("ded", displayMode: .inline) .navigationBarItems(leading: Button("lead"){}) } } }
我們只需要給NavigationLink提供跳轉的目標界面和需要點擊的控件,其他的NavigationLink會自己完成,雖然Text是一個靜態的文本控件,但是這里NavigationLink給他提供了點擊的能力。
- navigationBarItems:用來設置導航欄的左右按鈕
- navigationBarTitle:導航欄的標題及樣
- Inline:展示標準導航欄的title樣式
- large:系統默認的樣式,居左大標題
- automatic:繼承前一個頁面的導航欄樣式
為什么navigationBarTitle是被添加在附屬視圖上面,而不是直接添加在navigationView上?
每個頁面都需要一個title,這里設置的是當前頁面的title而不是整個navigationView的title,一個navigationView中可能會有很多個頁面,當其處于navigationView中時這個title就會被展示出來,但是navigationView本身并沒有處于一個導航視圖中,沒有視圖棧,所以無法顯示。
Modifier
在SwiftUI中,對視圖屬性的設置被稱為視圖的修飾器(Modifier),通常來說Modifier可以修改的內容包括以下幾個方面:
- 布局:通過調整視圖的大小、位置、對齊、填充等來告訴視圖如何在視圖層次結構中布局自己。
- 渲染:影響系統繪制視圖,例如對視圖進行縮放、遮罩,以及應用圖形效果等等。
- 樣式:指示如何樣式化視圖中包含的文本、控件和其他內容,多用于復雜視圖,如選擇器等等。
- 其他:前三個基本屬于配置視圖的范圍,剩下還包含一些添加手勢、呈現彈窗、或是事件處理等等雜七雜八但也是很重要的一部分。
struct ContentView: View {
var body: some View {
Text("Hello World")
.font(.largeTitle)
.foregroundColor(.white)
.padding()
.background(Color.blue)
.clipShape(RoundedRectangle(cornerRadius: 10))
}
}
除了系統內置的Modifier之外,我們也可以使用ViewModifier協議把一系列的Modifier封裝起來,來實現我們自定義的Modifier,起到簡化代碼,代碼復用,增加可讀性的作用:
struct Title: ViewModifier {
func body(content: Content) -> some View {
content
.font(.largeTitle)
.foregroundColor(.white)
.padding()
.background(Color.blue)
.clipShape(RoundedRectangle(cornerRadius: 10))
}
}
struct ContentView: View {
var body: some View {
Text("Hello World")
.modifier(Title())
}
}
聲明式布局
例子:指定兩個朋友幫你通關游戲
- 朋友A:你只需要告訴他目標,把這個游戲玩通關,他會自己去摸索如何打怪升級,如何買裝備等,不用你再手把手教他怎么玩。
- 朋友B:不關心目標,你說什么他做什么,說一步做一步,需要你一步步指導他去玩,直到通關。
聲明式布局體現了一種Coder do less, Framework do more的工作思想。它描述目標的性質,讓計算機明白目標,而非流程,底層的軟件/框架去解決如何實現他們;與之對立的是命令式布局,我們告訴計算機的是一個個指令,先做什么,再做什么,最后做什么,計算機不理解我們的目標,而只是按照我們的命令一步步去執行。
比如我們要在屏幕上放一張圖片,兩種方式的不同表現形式如下:
- 聲明式布局
- 只告訴系統屏幕上的什么位置有一張什么圖片,并不關心具體如何實現,這是框架要做的事情。
//聲明式布局
struct ContentView: View {
var body: some View {
Image("chilkoottrail")
}
}
- 命令式布局
- 初始化一個UIImageView
- 設置frame
- 添加到視圖樹中
//命令式布局
- (UIImageView *)imageView {
if (!imageView) {
_imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"chilkoottrail"]];
_imageView.frame = CGRectMake(12, 12, 100, 100);
}
return _imageView;
}
同步預覽
使用Xcode中的canvas,可以讓我們在使用SwiftUI編寫界面的同時觀察到實現的效果,代碼中的視圖會立即以預覽形式顯示,Canvas 常規的顯示規則是,總是顯示當前編輯器里可預覽的文件,使用左下角的 Pin Preview,可以在切換不同文件的時保持顯示被 pin 時候的 Preview 界面。
Inspector
使用Canvas不僅可以預覽界面的布局效果,也還可以在預覽界面中對視圖的屬性進行修改,代碼中會馬上出現對應的內容。通過在canvas里雙擊選中元素,在右側的Inspector里進行修改,inspector是一個可視化的編輯器,可以在其中進行某個控件屬性的修改,或者添加新的Modifier。
默認會顯示的內容有下面四種:
- 視圖類型
- Padding
- Frame
- Add Modifier
Add Modifier 中包含最豐富的內容,當不知道當前選中的對象有哪些方法時,Add Modifier 的彈窗是個非常好的查詢入口。Xcode 自動把 Modifier 分為:
- Control (多為可響應用戶事件的元素)
- Layout(布局、背景、大小尺寸信息)
- Effect(顏色對比、漸變、形變等)
- Event (顯示隱藏、通知到達等)
- Style(系統組件的默認樣式配置)
- ......
可視化修改、生成視圖
SwiftUI代碼中我們可以通過按住Command鍵,點擊對應的控件,來修改或者添加新的視圖,也可以通過該方法添加一些視圖容器來修改視圖的布局。
目前支持的一些actions:
- 包裹在 HStack 容器里
- 包裹在 VStack 容器里
- 包裹在 List 容器里
- 包裹在 Group (非容器)里
- 引入條件
- 使循環 n 次(默認 5 次)
- 呼出本視圖元素的 Inspector(這樣可以隱藏最右側的 attribute inspector 最大化屏幕利用率)
平臺支持
SwiftUI良好的跨平臺特性指的是它編寫的一套界面代碼可以同時運行在iOS,macOS以及tvOS等蘋果公司的各系統中,完全無需引入任何 UIKit APPKit WatckKit 等相關Framewok。
它將整個原有的平臺差異部分抽象為 App 和 Scene,對于一個 mac/iOS/iPad/watch/tv應用來說, App 代表了整個應用,Scene 代表了與 Window 相關的多窗口,有些設備只有一個 Scene 有些則有多個,雖然不同的 OS 確實存在差異,但是在語義層面達到了一致。
但是蘋果也特意指出,沒有一種方法能萬能的適配到所有設備上。如果有勢必會抹掉很多該平臺特有的體驗。這雖然對開發者友好,但可能會降低用戶的體驗。
針對多設備的設計理念:
- 針對對應用的平臺選擇對應的合適的設計
- 認真分析共享模塊的設計
- 共享視圖是個有風險的行為,要考慮的更加深入
- Learn once apply anyware
SwiftUI的布局算法
SwiftUI會通過body的返回值獲取描述視圖的控件信息,轉換為對應的內部視圖信息,交給2D繪圖引擎Metal或者Open GL繪制。
- ContentView
import SwiftUI
struct ContentView : View {
var body: some View {
Text("Hello World!")
}
}
上面這段代碼的視圖層級是RootView -> ContentView -> Text,關于Text出現在屏幕上的官方描述是:
- 父視圖為子視圖提供預估尺寸(建議尺寸)
- 子視圖計算自己的實際尺寸(一般有三種方式)
- 無需計算,根據內容推斷,如 Image 是和圖片等大,Text 是計算出來的可視范圍,類似 NSString 根據字體計算寬高。
- Frame 強制指定寬高
- 設置縮放比例 如 Image 設置 aspectRatio
- 父視圖根據子視圖的尺寸將子視圖放在自身的坐標系中,默認居中
- 使用Modifier的布局結構:
import SwiftUI
struct ContentView : View {
var body: some View {
Text("Hello World!")
.padding(10)
.background(Color.Green)
}
}
struct Avocado : View {
var body: some View {
Image("20x20_avocado")
.frame(width: 30, height: 30)
}
}
WWDC 20
跨平臺
swiftUI2.0在創建新工程時,會生成一套全新的模板基于SwiftUI App Lifecycle 的跨平臺項目。下面是新舊代碼的對比。
- Before:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView()
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
}
- After:
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Xcode Library
對于一個大型的開發團隊而言,一個開發同學是很難知道公司內到底有多少種組件庫,而且即便知道有某種組件庫,開發同學初期看到的也是代碼,一般需要書寫一定的 Demo 才可以用眼睛感知到這個組件到底是否是我想要的。
在 Xcode 12 中提供了更強大的工具,一個自定義組件,只需要遵守一個 LiberyContentProvider 協議就可被Xcode識別,可以像系統控件一樣直接從 Xcode 里面識別并預覽。對于一個大型團隊來說,此功能可以大大提高找尋組件和查看組件樣式的效率。
大列表組件
對于傳統的命令式編程來說,我們可以主動控制 UITableViewCell 的重用,自建緩沖池等一系列手段去優化我們的 APP 內存占用,但是對于 SwiftUI 1.0 來說,系統提供的控件并沒有有效的辦法去讓我們控制頁面的渲染,對于大列表頁面就容易出現內存占用過高問題。SwiftUI 2.0 推出了 LazyHStack 和 lazyVStack 加上 List 渲染模式默認就是 Lazy 的直接解決了最大的性能問題。
SwiftUI vs UIKit
- 安全性:SwiftUI基于Swift語言,Swift的引入會讓代碼盡可能的減少未定義的行為,減少crash。APP的穩定性就會得到提高,用戶會獲得更好的使用體驗。
- 包大小:如果一個APP的UI部分全部使用SwiftUI來編寫,這種聲明式的編程語言代碼量會小于傳統的命令式語言,所以整個APP的包大小也會降低,或者說相同的包大小就可以承載更多的業務。
- 開發體驗和效率:
- UI的調整可以及時得到反饋,這對于微小的UI微調工作是一個極大的幫助,節省時間。
- 支持的可視化編輯工具也為開發人員的工作帶來了很大的便利。
- Coder do less, Framework do more。
- 內存:Swift語言使用值類型構建app,減少了指針的使用,減少了大量堆內存的消耗,降低了APP的整體內存消耗。
- 局限性
- 只支持iOS13及以上的系統,而目前市場上很多APP還在支持iOS9。
- 不夠成熟,從去年WWDC19被提出來到現在只經過了一年多的發展,還沒有經歷過大型APP的考驗。
參考文檔
https://www.jianshu.com/p/f728dd085593
https://www.jianshu.com/p/8d8c9702ff0a
https://mp.weixin.qq.com/s/4TwguxVfjqHz-YLen-vh7A
https://developer.apple.com/cn/xcode/swiftui/
https://developer.apple.com/tutorials/swiftui/creating-and-combining-views
智能推薦
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...
styled-components —— React 中的 CSS 最佳實踐
https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...
19.vue中封裝echarts組件
19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...
猜你喜歡
【一只蒟蒻的刷題歷程】【藍橋杯】歷屆試題 九宮重排 (八數碼問題:BFS+集合set)
資源限制 時間限制:1.0s 內存限制:256.0MB 問題描述 如下面第一個圖的九宮格中,放著 1~8 的數字卡片,還有一個格子空著。與空格子相鄰的格子中的卡片可以移動到空格中。經過若干次移動,可以形成第二個圖所示的局面。 我們把第一個圖的局面記為:12345678. 把第二個圖的局面記為:123.46758 顯然是按從上到下,從左到右的順序記錄數字,空格記為句點。 本題目的任務是已知九宮的初態...
dataV組件容器寬高發生變化后,組件不會自適應解決方法
項目中需要大屏幕數據展示,于是使用了dataV組件,但是使用是發現拖動瀏覽器邊框,dataV組件顯示異常,如圖: 于是查了官網,官網的解釋如下: 于是按照官網的意思編寫代碼: 于是可以自適應了...
CSS3干貨10:如何做一個板塊標題水平線左邊帶顏色效果
很多網站在設計欄目標題的時候,喜歡用下劃線分開欄目標題和內容部分。 而且線條左邊的部分往往還有顏色,且這個顏色跟標題的文字長短保持一致。效果如圖所示: 這種效果其實很簡單。 我這里給大家推薦兩種方式: 假定我們的標題部分 HTML 結構如下: 方式一:利用下邊框。灰色部分是 h1 的下邊框,藍色部分是 span 標簽的下邊框。 h1 的高度為 40px,span 也設置它的高度為 40px。這樣,...
拜師————python基礎入門——程序的構成,對象,引用,棧內存和堆內存,標識符命名規則——day4
第九節課:任務9:009.程序的構成 Python程序的構成,一個程序是由什么構成的 1.python程序由模塊組成 , 一個模塊對應一個python源文件,(文件后綴名.py) 2.模塊由語句構成 運行程序時,安裝模塊中語句的順序依次執行。 代碼的組織和縮進 “龜叔”在設計python時,直接通過縮進來組織代碼 縮進時,幾個空格都是允許的,但是空格數必須統一,我們通常用四...