UICollectionView invalidateLayout不会在屏幕方向更改时触发sizeForItem

时间:2017-10-31 22:18:39

标签: ios swift uicollectionview

我有一个UICollectionViewController,它有一堆单元格,每个单元格都有屏幕大小。

如果我以纵向或横向方式启动应用程序,一切都会按预期工作。

问题是当我更改屏幕方向时,我调用collectionViewLayout.invalidateLayout()单元格大小保持原样,不调整大小。

我不知道为什么会这样。

这里有一些代码:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    print("size for item")
    return CGSize(width: view.frame.width, height: view.frame.height)
}


override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
    coordinator.animate(alongsideTransition: { (_) in
        self.collectionViewLayout.invalidateLayout() // layout update
    }, completion: nil)
}

在第一次加载时,我从尺寸设置中获取打印件,但在更改方向后,它没有调用它,因此当我更改方向时,单元格尺寸不适合屏幕,因为它适合在发布会上。

任何想法可能导致这个或我在这里做错了什么?

谢谢

修改

不知何故,我试图在willTransition函数中插入一个print语句,我注意到它并没有触发屏幕旋转。我认为问题出在那里而不是invaldateLayout(),因为它永远不会触发。

如何不自动调用覆盖功能?

3 个答案:

答案 0 :(得分:2)

我可以推荐的是覆盖布局类并实现shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool

class CollectionViewLayoutSelfSizingCells : UICollectionViewFlowLayout 
{    
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        if let collectionView = self.collectionView {
            return collectionView.frame.size != newBounds.size
        }

        return false
    }
}

这是我发现的最好的解决方案,它适用于整个项目。 说实话,我很惊讶UICollectionViewFlowLayout

上没有默认值

答案 1 :(得分:2)

您应该实施func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)方法。只要视图控制器的大小发生变化(例如,纵向和横向旋转时),就会调用此方法:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    coordinator.animate(alongsideTransition: { (_) in
        self.collectionViewLayout.invalidateLayout() // layout update
    }, completion: nil)
}

答案 2 :(得分:2)

UICollectionViewFlowLayoutInvalidationContext上有一个专用标志,称为invalidateFlowLayoutDelegateMetrics。文档内容如下:

此属性的默认值为false。如果由于任何项目大小的更改而使布局无效,则将此属性设置为true。 如果将此属性设置为true,则流布局对象将重新计算其项目和视图的大小,并根据需要查询该信息的委托对象。

在流layotu子类中提高标志。

class CollectionViewFlowLayout: UICollectionViewFlowLayout {

    override func invalidationContext(forBoundsChange newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext {
        let context = super.invalidationContext(forBoundsChange: newBounds) as! UICollectionViewFlowLayoutInvalidationContext
        if let collectionView = collectionView {
            context.invalidateFlowLayoutDelegateMetrics = collectionView.bounds.size != newBounds.size
        }
        return context
    }
}