当项目大小是自动的并且显示标题时,UICollectionView 崩溃
Posted
技术标签:
【中文标题】当项目大小是自动的并且显示标题时,UICollectionView 崩溃【英文标题】:UICollectionView crashes when item size is automatic and header is shown 【发布时间】:2021-12-28 03:36:26 【问题描述】:当我想将UICollectionView
的estimatedItemSize
属性设置为UICollectionViewFlowLayout.automaticSize
并同时显示一个节标题时,我遇到了一个奇怪的错误。
使用下面的代码,应用程序可以正确显示UICollectionView
。但是,一旦用户在UICollectionView
上滚动,应用程序会因递归调用函数updateVisibleCellsNow
而崩溃。
通过将estimatedItemSize
从automaticSize
设置为none
,我从另一个 *** 问题中找到了解决方法。但是,我想将自动布局功能设置为UICollectionViewCell
,而不是自己计算单元格高度。有没有更好的解决方案?谢谢。
这是我关于 ViewController 的代码
import UIKit
class DemoCollectionViewController: UIViewController
lazy private var collectionView: UICollectionView = [weak self] in
guard let strongSelf = self else return UICollectionView()
// Setup of `UICollectionViewFlowLayout`
let flowLayout = UICollectionViewFlowLayout()
// ********* This is the line that causes crash *********
flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
// ******************************************************
flowLayout.headerReferenceSize = CGSize(width: getScreenWidth(), height: 44.0)
flowLayout.sectionHeadersPinToVisibleBounds = true
// Setup of `UICollectionView`
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout).disableFrameToAutoLayout()
collectionView.dataSource = strongSelf
collectionView.register(ProfileThumbnailCollectionViewCell.self, forCellWithReuseIdentifier: "cellId")
collectionView.register(UICollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "headerId")
return collectionView
()
override func viewDidLoad()
super.viewDidLoad()
// Setup of the UICollectionView
view.addSubview(collectionView)
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
collectionView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
collectionView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor),
])
extension DemoCollectionViewController: UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int
return 10
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return 20
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! ProfileThumbnailCollectionViewCell
cell.contentView.backgroundColor = .yellow
return cell
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
switch kind
case UICollectionView.elementKindSectionHeader:
let supplementaryView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "headerId", for: indexPath)
supplementaryView.backgroundColor = .red
return supplementaryView
default:
return UICollectionReusableView()
这是我关于ProfileThumbnailCollectionViewCell
的代码:
class ProfileThumbnailCollectionViewCell: UICollectionViewCell
private let profileThumbnailImageView: UIImageView =
let profileThumbnailImageView = UIImageView()
profileThumbnailImageView.translatesAutoresizingMaskIntoConstraints = false
profileThumbnailImageView.backgroundColor = .red
profileThumbnailImageView.layer.cornerRadius = 60
profileThumbnailImageView.layer.masksToBounds = true
return profileThumbnailImageView
()
private let editPenButton: UIButton =
let editPenButton = UIButton()
editPenButton.translatesAutoresizingMaskIntoConstraints = false
editPenButton.backgroundColor = .mainGreen
editPenButton.layer.cornerRadius = 16
editPenButton.layer.masksToBounds = true
return editPenButton
()
override init(frame: CGRect)
super.init(frame: frame)
// Content View
contentView.backgroundColor = .yellow
NSLayoutConstraint.activate([
contentView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width)
])
// Profile Thumbnail ImageView
contentView.addSubview(profileThumbnailImageView)
NSLayoutConstraint.activate([
profileThumbnailImageView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
profileThumbnailImageView.widthAnchor.constraint(equalToConstant: 120),
profileThumbnailImageView.heightAnchor.constraint(equalToConstant: 120),
profileThumbnailImageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 25),
profileThumbnailImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -25)
])
// Edit thumbnail pen ImageView
contentView.addSubview(editPenButton)
NSLayoutConstraint.activate([
editPenButton.widthAnchor.constraint(equalToConstant: 32),
editPenButton.heightAnchor.constraint(equalToConstant: 32),
editPenButton.rightAnchor.constraint(equalTo: contentView.rightAnchor),
editPenButton.rightAnchor.constraint(equalTo: contentView.rightAnchor)
])
required init?(coder: NSCoder)
fatalError("This class should be inited from code instead of a nib file; init(coder:) has not been implemented")
【问题讨论】:
updateVisibleCellsNow 中有什么。你能分享完整的代码吗.. 嗨,updateVisibleCellsNow
是UICollectionView
的私有函数。因此,我无法访问代码。
我有一个类似的问题,并注意到将 sectionHeadersPinToVisibleBounds
设置为 false 可以修复崩溃。暂时没有找到替代品。
编辑:切换到 CompositionalLayout 似乎可以解决我的问题
【参考方案1】:
在 ViewDidLoad 中调用 registerNib
func registerNib()
let nib = UINib(nibName: "ProfileThumbnailCollectionViewCell", bundle: nil)
self.collectionView.register(nib, forCellWithReuseIdentifier: "ProfileThumbnailCollectionViewCell")
【讨论】:
嗨,通过 NIB 或通过代码创建UICollectionViewCell
没有区别。错误仍然出现。【参考方案2】:
在调查了几个小时后,我无意中找到了一个变通的解决方案,但这肯定不应该被视为最终解决方案。
class ProfileThumbnailCollectionViewCell: UICollectionViewCell
override init(frame: CGRect)
super.init(frame: frame)
// Content View
contentView.backgroundColor = .yellow
// ******** This is the weird point ********
let targetCellWidth = UIScreen.main.bounds.width - 1
NSLayoutConstraint.activate([
contentView.widthAnchor.constraint(equalToConstant: targetCellWidth)
])
UICollectionView
不会引发任何错误,并正确显示标题视图和UICollectionView
。
如果您对这种情况有任何想法,请在此处留下您的评论。非常感谢您的信息!谢谢!
【讨论】:
以上是关于当项目大小是自动的并且显示标题时,UICollectionView 崩溃的主要内容,如果未能解决你的问题,请参考以下文章
如何使用viewForSupplementaryElementOfKind - swift显示UICollectionView的特定单元格
在布局之间制作动画时,自动布局不会调整 Uicollectionviewcell 项目的大小