我有一个带有自定义 UICOllectionViewLayout 的 UICollectionViewSubclass
如何最好地处理方向更改时的 itemSize 更改?
class CollectSubclass: UICollectionView {
/// When orientation changes, then invalidate the layout
open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if ((traitCollection.verticalSizeClass != previousTraitCollection?.verticalSizeClass) || (traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass)) {
collectionViewLayout.invalidateLayout()
}
}
}
一旦布局因方向改变而失效,
我将单元格的 size.width
计算为 UICollectionView 的 width
。
这在 iPhone 7 Plus 模拟器上运行良好,但在 iPhone 7、5、SE 等较小的模拟器上失败。
似乎一旦 invalidateLayout
被调用,下面的函数就会被触发
/// Lays out subviews.
override open func layoutSubviews() {
super.layoutSubviews()
}
此函数依次调用 UICollectionViewLayout
子类上的 prepare
函数,我在其中使用 collectionView 的新框架来计算单元格的大小。
在 iPhone-7-Plus 上,traitCollectionDidChange
被触发一次。并且layoutSubviews
被触发一次导致prepare
被触发一次。
然而,在较小的模拟器上,traitCollectionDidChange
被触发一次,但 layoutSubviews
被触发两次。
随着 layoutSubviews
的第一个触发器,UICOllectionView 帧大小几乎应该是什么。在第二次触发时,UICOllectionView 框架大小现在是它应该的正确大小。
使用两种不同的帧尺寸被调用两次将使我准备两次布局(这是非常昂贵的)。
我在继承 UICOllectionViews 和 UICollectionViewLayouts 时遗漏了什么吗?感谢您的帮助。
如果需要我也可以提供示例工程
最佳答案
如果在您的设置中,其中一个 UICollectionViewCells
的宽度仅基于 UICollectionView
的大小以及屏幕的大小和方向(并且没有其他因素),以下是设置 Collection View 单元格大小的简洁方法:
1) 首次加载 View 时,预先计算纵向和横向单元格的大小。同时创建一个变量 currCellDimensions
来保存单元格的当前尺寸,并设置其初始值。
2) 沿这些行覆盖函数 viewWillTransitionToSize:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
setCurrentCollectionCellDimensions(size) // This code executes before the rotation begins, but "size" is the size that the main view is going to be after the rotation occurs. As of iOS 8, the size of an object swaps its width and its height when the UI changes its orientation.
}
3) 实现 setCurrentCollectionCellDimensions():
func setCurrentCollectionCellDimensions(newSize: CGSize) {
if (newSize.width < newSize.height) {
// set currCellDimensions to what it should be in portrait orientation
} else {
// set currCellDimension to what it should be in landscape orientation
}
if collectionView != nil {
collectionView.collectionViewLayout.invalidateLayout() // To trigger sizeForItemAtIndexPath to recalculate cell sizes
collectionView.reloadData() // To trigger cellForItemAtIndexPath to redraw the cells that are visible to the user. Without this call, the cell layout looks wrong on some iPhones.
}
}
4) 最后,让 sizeForItemAtIndexPath()
返回 currCellDimensions
。
关于ios - 如何在方向更改时正确处理 UICollectionViewLayout 的 itemSize,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42826342/