iOS 14.3 上的 UICollectionViewCompositionalLayout 错误

dra*_*kon 17 uikit ios uicollectionview swift uicollectionviewcompositionallayout

我在iOS 14.3上遇到了一个奇怪的布局问题,UICollectionViewCompositionalLayout在我的情况下使用集合视图与UICollectionViewDiffableDataSource. 问题是_UICollectionViewOrthogonalScrollerEmbeddedScrollView当您有一个正交截面时内部的错误位置,然后是固有高度截面。

幸运的是,我能够很容易地重现这个问题。考虑拥有此数据源:

private var dataSource: UICollectionViewDiffableDataSource<Section, String>!

enum Section: Int, Hashable, CaseIterable {
    case first = 0
    case second = 1
}
Run Code Online (Sandbox Code Playgroud)

对于每个部分,您创建以下布局:

private extension Section {
    var section: NSCollectionLayoutSection {
        switch self {
        case .first:
            let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50))
            let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
            let section: NSCollectionLayoutSection = .init(group: group)
            return section
        case .second:
            let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(200), heightDimension: .absolute(200))
            let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
            let section: NSCollectionLayoutSection = .init(group: group)
            section.orthogonalScrollingBehavior = .continuous
            section.contentInsets = .init(top: 10, leading: 10, bottom: 10, trailing: 10)
            section.interGroupSpacing = 10
            return section
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

打破了布局的是有进入.first部分都itemSizegroupSize.estimated高度。

您可以在iOS 14.3上看到下面的结果:乍一看布局在视觉上是正确的,但您立即意识到它已损坏的事实,因为内部滚动视图位于错误的位置。这意味着水平滚动错误地发生在蓝色区域。

破碎的布局 iOS 14.3

运行与 iOS 14.2完全相同的代码您将获得正确的布局。 正确布局

你怎么看这个问题?我是否遗漏了什么,或者它可能是 UIKit 的错误?

谢谢

sft*_*hrd 11

我们有估计高度的标题,并且_UICollectionViewOrthogonalScrollerEmbeddedScrollView由于这种回归,一些部分被完全破坏了。所以这是一个在我们的案例中有效的解决方案

public final class CollectionView: UICollectionView {
    
    public override func layoutSubviews() {
        super.layoutSubviews()
    
        guard #available(iOS 14.3, *) else { return }
    
        subviews.forEach { subview in
            guard
                let scrollView = subview as? UIScrollView,
                let minY = scrollView.subviews.map(\.frame.origin.y).min(),
                minY > scrollView.frame.minY
            else { return }
    
            scrollView.contentInset.top = -minY
            scrollView.frame.origin.y = minY
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢分享,这似乎可以很好地解决这个问题+1 (2认同)

小智 6

我们的用例略有不同,其中带有滚动视图的部分也使用估计高度,因此我修改了 的softenhard解决方案以调整滚动视图的高度。

public final class CollectionView: UICollectionView {
    override public func layoutSubviews() {
        super.layoutSubviews()

        guard #available(iOS 14.3, *) else { return }

        subviews.forEach { subview in
            guard
                let scrollView = subview as? UIScrollView,
                let minY = scrollView.subviews.map(\.frame.origin.y).min(),
                let maxHeight = scrollView.subviews.map(\.frame.height).max(),
                minY > scrollView.frame.minY || maxHeight > scrollView.frame.height
            else { return }

            scrollView.contentInset.top = -minY
            scrollView.frame.origin.y = minY
            scrollView.frame.size.height = maxHeight
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*uch 6

对我来说,这个问题在 iOS14.314.4. 现在固定在iOS 14.5 beta1

尝试安装最新的 Xcode beta 版本12.5 beta并使用运行的模拟器进行测试iOS 14.5

Xcode 测试版链接:https : //developer.apple.com/download/