当内容太长时,具有 .estimated 宽度的组合布局项目会使应用程序崩溃
Posted
技术标签:
【中文标题】当内容太长时,具有 .estimated 宽度的组合布局项目会使应用程序崩溃【英文标题】:Compositional Layout item with .estimated width crashes app when content is too long 【发布时间】:2021-04-09 19:06:29 【问题描述】:我正在探索使用组合布局的奇妙世界,我发现了一个需要帮助的小情况。下面是一个简单的应用程序,它使用带有 CL 的 CollectionView 使用 UIListContentConfiguration
圆形单元格显示随机字符串。该项目的宽度是.estimated(30)
,所以我可以根据单元格的内容获得自定大小的单元格(宽度)。在我将字符数从 50 增加到 100 之前,这非常有效。(目前在 iPad Pro 9.7 上运行)。似乎 100 个字符超出了 CollectionView 的宽度,这使我的应用开始使用大量内存,直到由于同样的原因而崩溃。
如何重现:
将要显示的字符数更改为更大的数字。前任。
return (1...100).compactMap $0; return self.randomString(length: .random(in: 1..<150))
import UIKit
class ViewController: UICollectionViewController
private let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
private lazy var values : [String] =
return (1...100).compactMap $0; return self.randomString(length: .random(in: 1..<50))
()
private func randomString(length: Int) -> String
return String((0..<length).map _ in letters.randomElement()! )
var compositionalLayout : UICollectionViewCompositionalLayout =
let inset: CGFloat = 2
//Item
let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(30), heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
// Group
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
group.interItemSpacing = .fixed(4)
group.edgeSpacing = NSCollectionLayoutEdgeSpacing(leading: .fixed(4), top: .fixed(4), trailing: .fixed(0), bottom: .fixed(0))
// Section
let section = NSCollectionLayoutSection(group: group)
return UICollectionViewCompositionalLayout(section: section)
()
override func viewDidLoad()
super.viewDidLoad()
configureUI()
private func configureUI()
self.collectionView.collectionViewLayout = compositionalLayout
self.collectionView.dataSource = self
self.collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
extension ViewController
override func numberOfSections(in collectionView: UICollectionView) -> Int
return 1
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return values.count
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
var contentConfiguration = UIListContentConfiguration.valueCell()
contentConfiguration.text = values[indexPath.item]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.contentConfiguration = contentConfiguration
cell.backgroundColor = UIColor(red: .random(in: 0...1) , green: .random(in: 0...1), blue: .random(in: 0...1), alpha: 1)
cell.layer.cornerRadius = cell.frame.height / 2
return cell
【问题讨论】:
在我看来,问题不在于估计大小的用户,而在于使用 UIListContentConfiguration。因为您正在使用它,所以您无法限制标签可以增长的宽度。 好吧,你的评论给了我一些想法,包括我可以将标签的宽度约束限制为比 collection.frame.width 少几个点,如果标签 intrinsicContentSize.width 是大于 collectionView.frame.width 并且做到了!谢谢@matt 是的,这很明显,但我看不出您如何在将自己限制在 UIListContentConfiguration 的同时做到这一点,因为您无法从该方向直接访问标签。这就是我的观点。 你有@rudymatos 的任何解决方案吗? 【参考方案1】:这似乎是 Apple 组合布局中的一个错误。正如您在问题中所显示的那样,它很容易重现。当单元格的宽度超过集合视图的宽度时,应用程序会挂起,因为它在主线程上做了过多的工作。此时(当应用程序冻结或无响应时)您可以通过 XCode 停止执行,并看到 Apple 的内部 API 在不断分配内存的同时进入某种无限循环。因此最终崩溃......
不幸的是,解决方案/解决方法是将单元格的宽度限制在合理的范围内,这样它们就不会超过集合视图自身的宽度。也许使用自动布局规则,或者使用您从UICollectionViewCompositionalLayout
获得的布局信息,例如:
func createCompositionalLayout() -> UICollectionViewCompositionalLayout
return UICollectionViewCompositionalLayout (section, layoutEnvironment) -> NSCollectionLayoutSection? in
// use availableWidth variable to determine the max size for your cells
let availableWidth: CGFloat = layoutEnvironment.container.effectiveContentSize.width
...
... do some additional layout work
...
【讨论】:
以上是关于当内容太长时,具有 .estimated 宽度的组合布局项目会使应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章
不...当 UIButton (Swift) 中的文本太长时