iOS 中使用 FlexBox 佈局實現圖片九宮格

wtfbuff發表於2019-05-13

首發於公眾號

在 iOS 中官方支援的佈局方式是 AutoLayout,是一種基於控制元件之間相互約束關係的自動佈局工具。

官方的 AutoLayout 雖然用起來簡單,但是有兩個非常不方便的地方:

  1. 原生 API 介面使用不友好
  2. 約束越多效能損失越多

第1個問題可以使用第三方庫來解決,比如 SnapKit(swift)、Masonry(oc)。 效能問題則無解,對於混合佈局的 Cell 如果全部使用自動佈局就會看到很明顯的滑動卡頓。

對於複雜 Cell 佈局,程式設計師們為了追求極致的幀率,一般都採用手寫佈局,幀率是上去了而維護的成本也最高。

為了兼顧易用性和高效率,Facebook 開發並開源了自己的佈局庫:Yoga。

Yoga 是 FlexBox 的子集,並沒有全部實現 FlexBox,但是對於大部分應用場景已經足夠了。

接觸過前端開發的朋友對 FlexBox 佈局一定不陌生,CSS 寫 flex 佈局真的太方便了。

FlexBox 是不同於 AutoLayout 的佈局方式,FlexBox 是自約束,每個控制元件的位置都是相對於自身所在的 Box 相對佈局,這就不存在 AutoLayout 基於控制元件間約束的耦合。

Yoga 是基於手動佈局的方式,這樣效率就很高,而且效能損耗很小,而且使用很簡單,用過 Masonry 的同學可以很快上手。

使用方法:

override init(frame: CGRect) {
  super.init(frame: frame)
  contentView.configureLayout { (layout) in
  layout.isEnabled = true
}

override func layoutSubviews() {
  super.layoutSubviews()
   yoga.applyLayout(preservingOrigin: true)
}
複製程式碼

layout.isEnabled = true 開啟 yoga 佈局, 在 layoutSubviews 中使用 applyLayout 自動調整佈局。

這和手動佈局的流程是一樣的,可以看出來 yoga 本質上也是手動佈局,只是再也不用手算座標了。

yoga 同時也有很好的易用性,比如要實現一個簡單的九宮格,只需要簡單的設定一下佈局引數。

override init(frame: CGRect) {
  super.init(frame: frame)

  configureLayout { (layout) in
  layout.isEnabled = true
  }

  contentView = UIView(frame: bounds)
  addSubview(contentView)
  contentView.configureLayout { (layout) in
    layout.isEnabled = true
    layout.flexDirection = .row
    layout.flexWrap = .wrap
    layout.flexGrow = 1
  }

  for _ in 0...8 {
    let imageView = UIImageView(frame: .zero)
    imageView.backgroundColor = .orange
    contentView.addSubview(imageView)
    imageView.configureLayout { (layout) in
      layout.isEnabled = true
      layout.width = 86
      layout.height = 86
      layout.marginTop = 10
      layout.marginLeft = 10
    }
  }
}

override func layoutSubviews() {
  super.layoutSubviews()
  yoga.applyLayout(preservingOrigin: true)
}
複製程式碼

核心引數是 layout.flexWrap = .wrap ,讓檢視佈局自動換行,再計算好間距和寬高,這樣就實現了九宮格的排列效果。

執行的效果:

img

相關文章