In iOS 12, when does the UICollectionView layout c

2019-01-16 10:09发布

Same code like this

collectionLayout.estimatedItemSize = CGSize(width: 50, height: 25)
collectionLayout.itemSize = UICollectionViewFlowLayoutAutomaticSize
collectionLayout.minimumInteritemSpacing = 10 

for _ in 0 ..< 1000 {
    let length = Int(arc4random() % 8)
    let string = randomKeyByBitLength(length)
    array.append(string!)
}
collectionView.reloadData()

cell constraints:

enter image description here

when I run it on iOS 12, it's different. left simulator is iOS 11, and right is iOS 12:

enter image description here

But, when I scroll it, cells's frames will be normal.


Sample project to reproduce the issue: https://github.com/Coeur/StackOverflow51375566

7条回答
萌系小妹纸
2楼-- · 2019-01-16 11:12

The problem is that the feature being posited here — collection view cells that size themselves based on their internal constraints — does not exist. It has never existed. Apple claims that it does, but it doesn't. I have filed a bug on this every year since collection views were introduced and this claim was first made; and my bug reports have never been closed, because the bug is real. There is no such thing as self-sizing collection view cells.

See also my answer here: https://stackoverflow.com/a/51585910/341994\

In some years, trying to use self-sizing cells has crashed. In other years, it doesn't crash but it gets the layout wrong. But it doesn't work.

The only way to do this sort of thing is to implement the delegate method sizeForItemAt and supply the size yourself. You can easily do that by calling

cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)

on a model cell that you have configured in advance. That is what the runtime should be doing for you — but it doesn't.

So here's my solution to the original question. Instead of a simple array of strings, we have generated an array of string-size pairs (as a tuple). Then:

override func collectionView(_ collectionView: UICollectionView, 
    cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! MyCell
        cell.label.text = self.array[indexPath.row].0
        return cell
}

func collectionView(_ collectionView: UICollectionView, 
    layout collectionViewLayout: UICollectionViewLayout, 
    sizeForItemAt indexPath: IndexPath) -> CGSize {
        return self.array[indexPath.row].1
}
查看更多
登录 后发表回答