【问题标题】:UICollectionViewCompositionalLayout bug on iOS 14.3iOS 14.3 上的 UICollectionViewCompositionalLayout 错误
【发布时间】:2021-03-29 19:42:51
【问题描述】:

我在 iOS 14.3 上遇到了一个奇怪的布局问题,其中集合视图使用 UICollectionViewCompositionalLayout,在我的情况下与 UICollectionViewDiffableDataSource 结合使用。 问题在于内部_UICollectionViewOrthogonalScrollerEmbeddedScrollView 的位置错误,当您有一个正交部分之前有一个固有高度部分时。

幸运的是,我能够非常轻松地重现该问题。 考虑拥有这个数据源:

private var dataSource: UICollectionViewDiffableDataSource<Section, String>!

enum Section: Int, Hashable, CaseIterable {
    case first = 0
    case second = 1
}

为每个部分创建以下布局:

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
        }
    }
}

打破布局的事情是在itemSizegroupSize.estimated 高度进入.first 部分。

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

运行完全相同的代码直到 iOS 14.2 你得到正确的布局。

您对这个问题有什么看法? 我是否遗漏了什么或者可能是 UIKit 错误?

谢谢

【问题讨论】:

  • 嗨,matt,我们在一周前向 Apple 报告了这个问题,让我们等待答复。当我得到任何更新时,我会保持主题更新。谢谢你的回答。
  • 我们遇到了完全相同的问题。当NSCollectionLayoutDimensionestimatedHeight 设置为高于正在呈现的实际单元格的值时,似乎会发生这种情况。当您将estimatedHeight 设置为最小尺寸时,它会按预期工作,因此放大似乎有效,但缩小似乎会导致_UICollectionViewOrthogonalScrollerEmbeddedScrollView 定位错误。我们目前正在通过将estimatedHeight 包裹在if #available(iOS 14.3, *) { ... } else { ... } 之间来解决此问题。也在努力提交RADAR
  • 大家好,开发者技术支持回复我们说,collection view 团队已经意识到这个错误,并且应该在下一个 iOS 版本中发布修复。遗憾的是,他们没有向我们提供修复的预计发布日期。
  • 是否为此提交了 RADAR?如果可以,我想监控它
  • 我确实向 Apple 提出了问题,但它仍被标记为 Open 并且尚未经过整理。我刚刚检查了 Xcode 12.4 RC / iOS 14.4 RC,不幸的是问题仍然存在。

标签: ios swift uicollectionview uikit uicollectionviewcompositionallayout


【解决方案1】:

我们有估计高度的标题,并且由于这种回归,_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
        }
    }
}

【讨论】:

  • 感谢分享,这似乎很好地解决了这个问题+1
【解决方案2】:

对我来说,这个问题可以在 iOS 14.314.4 中重现。而且现在固定在iOS 14.5 beta1

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

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

【讨论】:

    【解决方案3】:

    我们有一个稍微不同的用例,带有滚动视图的部分也使用估计的高度,所以我修改了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
            }
        }
    }
    

    【讨论】:

    • 这个对我们来说也更有效,最初看起来和上一个一样有效,但由于问题的间歇性,有时会导致视图发生变化。
    • 认为它可以更好地修复它,但我们仍然间歇性地遇到问题。
    • 请更新代码以使用guard #available(iOS 14.3, *) else { return } 而不是此代码,因为它错误if #available(iOS 14.3, *) { return }
    • 谢谢@EhabSaifan。已更新。
    【解决方案4】:

    我遇到了同样的问题,其他答案的解决方法对我不起作用。

    所以我做了这个扩展来确定它是否是有问题的 iOS 版本:

    extension UICollectionView {
        static var isIosVersionWithSizeEstimationBug: Bool {
            if #available(iOS 14.5, *) {
                return false
            }
            if #available(iOS 14.3, *) {
                return true
            }
            return false
        }
    }
    

    在这种情况下,我使用它来使用绝对高度。它可能不是每个用例的解决方法。但对我来说,这是一个稳定的解决方案:

    let height: NSCollectionLayoutDimension = {
        let maxPossibleHeight: CGFloat = 280
        if UICollectionView.isIosVersionWithSizeEstimationBug {
            return .absolute(maxPossibleHeight)
        } else {
            return .estimated(maxPossibleHeight)
        }
    }()
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: height)
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/3), heightDimension: height)
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 1)
    let section = NSCollectionLayoutSection(group: group)
    

    【讨论】:

      猜你喜欢
      • 2021-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-22
      • 1970-01-01
      • 2021-05-14
      • 2020-12-05
      • 1970-01-01
      相关资源
      最近更新 更多