給SwiftUI找個替補 -- Lima

背景

今年的WWDC2019上最使人激動的新技術無疑就是全新的UI框架SwiftUI了。對於蘋果開發者來講,它爲你們開啓了一個美麗的新世界:git

  • 簡潔的聲明式語法。極致簡潔易讀,百行代碼變十行。
  • 統一蘋果旗下全部平臺。iOS,macOS,tvOS, watchOS。
  • 實時預覽,多設備同時預覽。修改代碼或預覽均可以動態生效。
  • 清晰的數據流管理。結合Combine框架實現響應式編程。

SwiftUI着實驚豔,但遺憾的是它要求iOS 13.0以上的系統。這一條約束讓你們以爲它還很遙遠,由於國內多數App還要適配iOS 9.0,甚至iOS 8.0。github

開源聲明式框架

其實,SwiftUI的核心在於聲明式語法描述界面,而聲明式語法並非什麼新鮮事物,著名的React和近來大熱的Flutter都採用了聲明式語法。筆者查找和比較了一些開源的聲明式界面框架,但願找到一個SwiftUI的合適替補,讓你們在本身現有的項目裏也能擁有相似SwiftUI的開發體驗。編程

Layout
國外大神出品,基於自定義的XML DSL語法,功能強大,完備,支持Live Reload,自帶工具集。swift

TemplateKit
類React框架,基於自定義的XML DSL語法,支持Live Reload。數組

LayoutKit
LinkedIn出品,質量性能放心。bash

ComponentKit
Facebook出品,使用Objective-C++編寫,異步高性能佈局,支持組件回收重用,優化內存和滑動性能。閉包

Render
類React框架,支持組件回收重用,優化內存和滑動性能。框架

Tokamak
類React框架。異步

Komponents 類React框架,聲明式語法比較簡潔,與SwiftUI較爲接近。工具

Few
類React框架。

Lima
超輕量級的框架,語法上與SwiftUI最爲接近。

方案選擇

這些框架都是在蘋果發佈SwiftUI以前誕生的。比較完一圈之後,我不禁得感嘆,仍是SwiftUI更優雅,更強大。這也不難理解,畢竟蘋果是後來者,SwiftUI是汲取了業界最新理念,厚積薄發的超越之做。

至於哪一個框架更值得推薦,我想應該是因人而異。熟悉React的朋友,能夠選擇類React框架;看重性能的朋友,能夠選擇兩個大廠的框架;須要實時預覽開發體驗的朋友,能夠考慮前兩個框架。而從我我的來講,我選擇『小而美』的Lima

它的優點以下:

  • 超輕量,源碼十分簡單易懂,方便自行擴展。
  • 語法上與SwiftUI最爲接近,簡潔易懂。
  • 徹底基於UIKit現有控件,沒有複雜的概念。

咱們來作個比較,看下Lima和SwiftUI實現下面的界面,它們的代碼各長得什麼樣:

SwiftUI

HStack {
   VStack {
       Text("★★★★★")
       Text("5 stars")
   }
   VStack {
       HStack {
           Text("Avocado Toast").font(.title)
           Spacer()
           Image("20x20_avocado")
       }
       Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").lineLimit(1)
   }
}
複製代碼

Lima

LMRowView(spacing: 10,
   LMColumnView(
       UILabel(text: "★★★★★", textAlignment: .center),
       UILabel(text: "5 stars", textAlignment: .center)
   ),
   LMColumnView(
       LMRowView(
           UILabel(text: "Avocado Toast", font:.preferredFont(forTextStyle: .title1)),
           LMSpacer(),
           UIImageView(image: UIImage(named: "20x20_avocado"))
       ),
       UILabel(text: "Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes")
   )
)
複製代碼

看起來是否是很像,並且仍是咱們熟悉的UIKit,簡直完美了。

Lima介紹

適用性

建議不要經過pod集成Lima,由於podspec上的Swift version和Deployment Target並不許確。實際上它的適用性是挺普遍的,能夠支持iOS 9.0以上系統,稍做修改,也能支持iOS 8.x。並且Swift 4.x和Swift 5.x均可以編譯經過。 另外,因爲源碼裏有Objective-C的代碼,因此純Swift的項目最好是集成編譯好的Lima.framework。

框架說明

經過上面的例子咱們也看到,Lima自己很簡單,很容易上手。這點和Masonry很像,你甚至無需預先學習AutoLayout,只是經過看幾個例子就能夠開始使用Masonry了。Lima也是如此一目瞭然,你也無需去學習SwiftUI,花兩個小時看一下項目首頁上的那個說明文檔,跑一下Demo,基本就能開始編碼了。

這裏,我給你們簡單理一下Lima的源碼。

  • Lima是對UIKit的封裝,內部經過AutoLayout實現佈局。

  • LMLayoutViewLMBoxView是容器類的抽象基類,並不直接調用。

  • LMRowViewLMColumnViewLMAnchorViewLMRootView是四個容器類。

    • LMRowView是水平容器;
    • LMColumnView是垂直容器;
    • LMAnchorView用於將子視圖排布在它的邊緣;
    • LMRootView一般用於控制器的根視圖,繞過系統定義的視圖Margins。
  • LMSpacer默認是當作空白,同時也能夠當作分隔線。

    LMSpacer(height: 0.5, backgroundColor: UIColor.gray)
    複製代碼
  • LMScrollViewLMTableViewCellLMTableViewHeaderFooterViewLMCollectionViewCell是UIKit相應類型的子類。它們都有一個content屬性,用於接收內容視圖,並且它們的大小自動由content視圖決定。

  • 對於經常使用的UIKit控件和上述Lima定義的類型,Lima都在擴展中給它們定義了便利構造器,咱們在聲明式語法中須要經過這些構造器聲明控件。

  • 每一個構造器的最後一個參數(with)都是一個參數爲自身的閉包。這讓咱們能夠在尾隨閉包裏獲取控件的實例,並設置更多的屬性。

    var detailView: LMColumnView!
    LMColumnView(margin: 8, verticalAlignment: .top, spacing: 0) {
       self.detailView = $0
       $0.clipsToBounds = true
    }
    複製代碼
  • 除了構造器,咱們還須要關注頭文件裏定義的屬性。視圖的排布是經過設置這些屬性實現的。

My Fork

建議有興趣嘗試Lima的朋友,使用筆者fork的源碼。

Lima

我這份源碼修改了一個可能的同名屬性覆蓋問題,而且對原始代碼作了一些擴展。

  • Lima在UIView的分類裏定義了width和height屬性。這兩個屬性名很容易致使同名屬性覆蓋的問題。咱們經常使用的YYKit裏就定義了這兩個屬性。因此,我給這兩個屬性加了lm_前綴。

  • 我給LMColumnView, LMRowViewLMAnchorView加了一個能夠接收子視圖數組的構造器,這樣能夠實現以下的調用:

    let items = ["First", "Second", "Third", "Four", "Five"]
    LMColumnView(
       items.map { item in
           UILabel(text: "Hello, \(item)!", textAlignment: .center)
       }
    )
    複製代碼
  • 我給UIButtonUITextField的構造器里加入了事件處理參數,方便調用:

    UIButton(title: "Press Me!", action: { [weak self] btn in
       self?.showGreeting()
    })
    複製代碼
  • 我添加了一個LMTableView類,指望實現SwiftUI裏簡單的List效果。

    SwiftUI

    List(landmarks) { landmark in
       HStack {
          Image(landmark.thumbnail)
          Text(landmark.name)
          Spacer()
          
          if landmark.isFavorite {
             Image(systemName: "star.fill")
                .foregroundColor(.yellow)
          }
       }
    }
    複製代碼

    Lima

    LMTableView(items, { item in
       LMTableViewCell(
           LMRowView(
               UILabel(text: "Hello, \(item)!"),
               LMSpacer(),
               UIImageView(image: UIImage(named: "EmailIcon")) {
                   if item == "Five" {
                       $0.isDisplayable = false
                   } else {
                       $0.isDisplayable = true
                   }
               }
           )
        )
    })
    複製代碼

    不過,個人實現Cell沒有作到重用,只適用於短列表。也歡迎你們繼續研究。

不足

Lima用簡單的代碼實現了接近SwiftUI的簡潔的聲明式語法。可是,它只能看作是一個簡化版的SwiftUI,遠沒有SwiftUI強大。

  • 沒有SwiftUI那樣漂亮的狀態和數據流實現。
  • 沒有SwiftUI那樣強大簡潔的列表實現。
  • 沒有SwiftUI那樣的動畫和繪圖實現。
  • 容器類會引入多餘的視圖層級,不太適合須要性能或內存利用率的場景。

總結

SwiftUI很強大,很美麗,可是咱們還用不起來它。因此,筆者但願找一個開源的聲明式UI框架,在現有的項目裏引入聲明式編程。筆者找到了Lima,並擴展了它。若是,你如今正在用Masonry佈局UI,我建議您不妨試試Lima,由於聲明式UI是將來的趨勢,並且Lima和Masonry同樣簡單易用,Lima比Masonry的代碼更加簡潔易讀。

Lima

相關文章
相關標籤/搜索