iOS 12 的坑:UICollectionViewCell autolayout self sizing 和 size 計算失效了

很久很久不寫博客了…… 一直在忙着搞公司的博客(打個小廣告,歡迎關注:),把本身的博客荒廢了 >< 可是最近遇到一個奇葩的 UI bug,很是無奈,當時在網上查了半天也沒查到,因此在這記錄一下。bash

問題表現

iOS 12 發佈以後,QA 開始給倉薯源源不斷地 assign UI 錯亂的 bug。我想這是全部工程師都頭疼的問題:幾百年沒改過的地方,忽然就有人給你報 bug 了。測了一下,發現都是 iOS 12 特有的 bug,初步認定是蘋果的鍋。具體有如下幾種症狀:ide

  1. 以前用 estimated item size 的頁面,好比說指定 estimated item size 高度是 80,但把真實數據填進去以後,self sizing 的 cell 真實高度是 100。因此正常應該顯示高度爲 100,以前都沒問題。到了 iOS 12 以後,忽然就不是 100 了,也不是 80 ,而是 60 多這樣一個奇怪的數……
  2. 以前好好的 cell 忽然消失了。看了下緣由,是 systemLayoutSizeFitting(UILayoutFittingCompressedSize).height) 返回 0。原本 20 多、30 多的 cell 統統返回 0。
  3. debugger 裏出來一大堆 constraint 衝突的 warning。仔細看一下,是多了一個莫名其妙的 constraint,不是我加的,不知道從哪裏來,優先級仍是 required。

能重現問題的 demo

下面是一個很是簡單的 demo,能重現出這類 bug。假設咱們有一個 SimpleCollectionViewCell,顧名思義,它是一個很是簡單的 collectionViewCell。裏面有個頂天立地的方塊,充滿這個 cell 的空間。ui

final class SimpleCollectionViewCell: UICollectionViewCell {

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

    let squareView = UIView(frame: .zero)
    contentView.addSubview(squareView)

    squareView.translatesAutoresizingMaskIntoConstraints = false
    squareView.heightAnchor.constraint(equalToConstant: 100).isActive = true
    squareView.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true
    squareView.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true
    squareView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
    squareView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
}
複製代碼

因此這個 square 的高度爲 100,四面 constraint 到 contentView。沒什麼問題吧?~ 下面咱們用 systemLayoutSizeFitting 來算它的高度:spa

class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    let measurementCell = SimpleCollectionViewCell(frame: .zero)
    let cellWidth = view.frame.width
    measurementCell.widthAnchor.constraint(equalToConstant: cellWidth).isActive = true
    let size = CGSize(width: cellWidth, height: measurementCell.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height)
    print(size)
  }
}
複製代碼

size 打印出來是多少呢?在 iOS 11 上打印出來 (320, 100) 沒問題。在 iOS 12 上打印出來就是 (320, 0) 了。debug

解決方法

Debug 的過程就懶得吐槽了。本覺得是個很常見的問題,但在網上查了一圈沒查到相關的東西,還覺得是本身工程的問題,繞了一圈…… 最後解決方法也很簡單:code

  1. 忽略 contentView,直接把 subView 加到 cell 上。不用 contentViewUITableViewCell 裏會有問題,在 collectionView 裏彷佛還沒發現什麼問題。
  2. 若是要用 contentView,須要在 init 里加幾行:
final class SimpleCollectionViewCell: UICollectionViewCell {

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

    contentView.translatesAutoresizingMaskIntoConstraints = false
    contentView.topAnchor.constraint(equalTo: topAnchor).isActive = true
    contentView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
    contentView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
    contentView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true

    let squareView = UIView(frame: .zero)
    ...
  }
}
複製代碼

看到這裏,這個 bug 的緣由就不言自明瞭……實在使人無語,爲啥 iOS 12 會有這樣一個改動呢。 不知道爲啥,此前在網上都沒有查到相關的內容,所以在這記錄一下,但願能有幫助。rem

相關文章
相關標籤/搜索