更改流布局的 itemSize 后单元格大小未更新

Cell size not updating after changing flow layout's itemSize

在我的应用中,我有一个全屏分页集合视图,每个单元格也需要全屏,所以集合视图布局的项目大小需要与视图控制器的视图边界大小相同.为此,在 viewDidLayoutSubviews 中,我只是设置项目大小,它按预期工作。当我显示此屏幕时,viewDidLayoutSubviews 被调用 3 次,每次 iPhone 7 的视图边界大小为 375.0 x 667.0。单元格的大小与预期的尺寸相同。

但是当使用 3D Touch peek 和 pop 呈现此屏幕时,cell 的大小不符合预期,无论是在 peeking 还是 popping 时。 viewDidLayoutSubviews 被调用 4 次,边界大小为:

--- peek triggered ---
375.0 x 569.524495677234
375.0 x 569.524495677234
375.0 x 720.821325648415
--- pop triggered ---
375.0 x 667.0

查看时,集合视图'full-screen'符合预期,高度为721,单元格的预期宽度为375,但单元格高度为569,而应为721。弹出时,集合视图高度按预期更改为 667,但单元格高度仍为 569。

我试过在设置 itemSize 后调用 collectionView.layoutIfNeeded() 但结果是一样的。为什么集合视图不在此处更新单元格大小?

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    print("\(view.bounds.width) x \(view.bounds.height)")

    let boundsSize = CGSize(width: Int(view.bounds.width), height: Int(view.bounds.height))
    let flowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout

    if flowLayout.itemSize != boundsSize {
        flowLayout.itemSize = boundsSize

        collectionView.layoutIfNeeded() //this doens't help
    }
}

尝试用 flowLayout.invalidateLayout()

替换 collectionView.layoutIfNeeded()
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    print("\(view.bounds.width) x \(view.bounds.height)")

    let boundsSize = CGSize(width: Int(view.bounds.width), height: Int(view.bounds.height))
    let flowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout

    if flowLayout.itemSize != boundsSize {
        flowLayout.itemSize = boundsSize

        debugPrint("Called")
        flowLayout.invalidateLayout()
    }
}

您可以将 collectionView(_:layout:sizeForItemAt:)viewDidLayoutSubviews 一起使用。

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    print("\(view.bounds.width) x \(view.bounds.height)")

    let boundsSize = CGSize(width: Int(view.bounds.width), height: Int(view.bounds.height))

    if !boundsSize.equalTo(self. collectionViewItemSize) {
        collectionView.invalidateLayout()
    }
}

var collectionViewItemSize:CGSize = .zero

func collectionView(_ collectionView: UICollectionView,
                    layout collectionViewLayout: UICollectionViewLayout,
                    sizeForItemAt indexPath: IndexPath) -> CGSize {
    self.collectionViewItemSize = CGSize(width: Int(view.bounds.width), height: Int(view.bounds.height));
    return self.collectiViewItemSize;
}

我最终更改了 viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) 中的 itemSize 并将大小传递给一个方法,该方法将根据视图的未来大小进行计算。

看来是UICollectionViewFlowLayout的bug, 我必须在 invalidateLayout()

之前调用 prepare()
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()


    guard let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else
    {
        return
    }

    layout.itemSize = cellSize
    layout.minimumLineSpacing = space
    layout.prepare()  // <-- call prepare before invalidateLayout
    layout.invalidateLayout()
}

将集合视图的 'Estimate Size' 从检查器更改为 'None'! None 以上答案对我有用。