ios - 如何在方向更改时正确处理 UICollectionViewLayout 的 itemSize

标签 ios swift uicollectionview uikit

我有一个带有自定义 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/

相关文章:

ios - 登录后如何在 swift 4 中使用主视图 Controller 设置侧菜单

ios - 如何在Xcode中进行Wi-Fi文件共享

ios - 使 UICollectionView 中的最后一个单元格填充宽度

javascript - React Native iOS - Hermes 在 Podfile 中启用,但在应用程序中未启用

ios - 如何在 UIProgressView 中设置进度色调颜色

ios - View 在方向更改时旋转时的黑色背景

swift - 将图像从 collectionView 共享到 Facebook - 可选值崩溃

iphone - 在横向模式下重新定位按钮 - 干净的方法?

ios - UIView TouchsBegan 未被调用

ios - Collection View 单元格的多项选择