• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 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出現在屏幕上的官方描述是:

    1. 父視圖為子視圖提供預估尺寸(建議尺寸)
    2. 子視圖計算自己的實際尺寸(一般有三種方式)
      1. 無需計算,根據內容推斷,如 Image 是和圖片等大,Text 是計算出來的可視范圍,類似 NSString 根據字體計算寬高。
      2. Frame 強制指定寬高
      3. 設置縮放比例 如 Image 設置 aspectRatio
    3. 父視圖根據子視圖的尺寸將子視圖放在自身的坐標系中,默認居中
    • 使用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://mp.weixin.qq.com/s?__biz=MzAxNDEwNjk5OQ==&mid=2650408836&idx=1&sn=e1cd3c705ba49aa8613b3adc21e14cd6&scene=21#wechat_redirect

    https://mp.weixin.qq.com/s?__biz=MzAxNDEwNjk5OQ==&mid=2650402891&idx=1&sn=804f271d6794a0ec7b5eeaea585f5e8e&scene=21#wechat_redirect

    https://mp.weixin.qq.com/s?__biz=MzI2NTAxMzg2MA==&mid=2247483748&idx=1&sn=ca06c93e207009d40e17bf2f95d76eb6&scene=21#wechat_redirect

    https://developer.apple.com/cn/xcode/swiftui/

    https://developer.apple.com/tutorials/swiftui/creating-and-combining-views

    版權聲明:本文為Mr_H9527原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/Mr_H9527/article/details/108396478

    智能推薦

    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 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...

    基于TCP/IP的網絡聊天室用Java來實現

    基于TCP/IP的網絡聊天室實現 開發工具:eclipse 開發環境:jdk1.8 發送端 接收端 工具類 運行截圖...

    19.vue中封裝echarts組件

    19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...

    猜你喜歡

    劍指Offer39-調整數組順序使奇數位于偶數前面

    一開始想著用冒泡排序的方法來做,但是bug還是很多,后來看了評論區答案,發現直接空間換時間是最簡單的,而且和快排的寫法是類似的。...

    【一只蒟蒻的刷題歷程】【藍橋杯】歷屆試題 九宮重排 (八數碼問題: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時,直接通過縮進來組織代碼 縮進時,幾個空格都是允許的,但是空格數必須統一,我們通常用四...

    精品国产乱码久久久久久蜜桃不卡