好久好久不寫部落格了…… 一直在忙著搞公司的部落格(打個小廣告,歡迎關注:),把自己的部落格荒廢了 >< 但是最近遇到一個奇葩的 UI bug,非常無奈,當時在網上查了半天也沒查到,所以在這記錄一下。
問題表現
iOS 12 釋出之後,QA 開始給倉薯源源不斷地 assign UI 錯亂的 bug。我想這是所有工程師都頭疼的問題:幾百年沒改過的地方,突然就有人給你報 bug 了。測了一下,發現都是 iOS 12 特有的 bug,初步認定是蘋果的鍋。具體有以下幾種症狀:
- 之前用 estimated item size 的頁面,比如說指定 estimated item size 高度是 80,但把真實資料填進去之後,self sizing 的 cell 真實高度是 100。所以正常應該顯示高度為 100,之前都沒問題。到了 iOS 12 之後,突然就不是 100 了,也不是 80 ,而是 60 多這樣一個奇怪的數……
- 之前好好的 cell 突然消失了。看了下原因,是
systemLayoutSizeFitting(UILayoutFittingCompressedSize).height)
返回 0。本來 20 多、30 多的 cell 通通返回 0。 - debugger 裡出來一大堆 constraint 衝突的 warning。仔細看一下,是多了一個莫名其妙的 constraint,不是我加的,不知道從哪裡來,優先順序還是 required。
能重現問題的 demo
下面是一個非常簡單的 demo,能重現出這類 bug。假設我們有一個 SimpleCollectionViewCell,顧名思義,它是一個非常簡單的 collectionViewCell。裡面有個頂天立地的方塊,充滿這個 cell 的空間。
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
來算它的高度:
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 的過程就懶得吐槽了。本以為是個很常見的問題,但在網上查了一圈沒查到相關的東西,還以為是自己工程的問題,繞了一圈…… 最後解決方法也很簡單:
- 忽略
contentView
,直接把 subView 加到 cell 上。不用contentView
在UITableViewCell
裡會有問題,在 collectionView 裡似乎還沒發現什麼問題。 - 如果要用
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 會有這樣一個改動呢。
不知道為啥,此前在網上都沒有查到相關的內容,因此在這記錄一下,希望能有幫助。