UICollectionView 将在调用“reloadItems”方法时重新创建单元格
Posted
技术标签:
【中文标题】UICollectionView 将在调用“reloadItems”方法时重新创建单元格【英文标题】:UICollectionView will recreate cells when calling the "reloadItems" method 【发布时间】:2018-11-09 03:51:16 【问题描述】:我的单元格有一个从网络下载的图像,因此我需要将单元格的高度设置为动态。
图片下载完成后,我将调用self.collectionView.reloadItems(at: [indexPath])
触发设置新高度的委托方法。
但似乎reloadItems
方法会重新创建一个单元格,而不仅仅是重新布局一个原来的重用单元格。
我该如何解决这个问题?是苹果的 UICollectionView 上的错误还是我做错了什么?
完整代码:
// code from ViewController
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: AnnounmentWallCollectionViewCell.cellIdentifier, for: indexPath) as! AnnounmentWallCollectionViewCell
let announcement = announcements[indexPath.row]
cell.collectionView = collectionView
cell.setBanner(from: announcement.banner, indexPath: indexPath, completion: [unowned self] (height) in
self.bannersHeight[indexPath.row] = height
)
cell.sethtmlContent(announcement.content)
contentsHeight[indexPath.row] = cell.htmlContentSize.height
printD("indexPath: \(indexPath)")
return cell
// code from cell
func setBanner(from url: URL?, indexPath: IndexPath, completion: @escaping (_ height: CGFloat)->())
// URL(string: "https://i.imgur.com/qzY7BJ9.jpg")
if let url = url
if let banner = SDImageCache.shared().imageFromDiskCache(forKey: url.absoluteString)
self.bannerView.isHidden = false
self.bannerView.image = banner.scaleWidth(to: self.bounds.width - 32) // leading + trailling
self.bannerHeight.constant = self.bannerView.image?.size.height ?? 1
completion(self.bannerHeight.constant)
printD("NO Download: \(indexPath)")
let animationsEnabled = UIView.areAnimationsEnabled
UIView.setAnimationsEnabled(false)
self.collectionView.reloadItems(at: [indexPath])
UIView.setAnimationsEnabled(animationsEnabled)
else
DispatchQueue.global().async
SDWebImageDownloader.shared().downloadImage(with: url, options: .useNSURLCache, progress: nil) (banner, data, error, finished) in
DispatchQueue.main.async
if let banner = banner
SDImageCache.shared().store(banner, forKey: url.absoluteString, toDisk: true)
self.bannerView.isHidden = false
self.bannerHeight.constant = banner.scaleWidth(to: self.bounds.width - 32)?.size.height ?? 1
completion(self.bannerHeight.constant)
self.collectionView.reloadData()
printD("Download: \(indexPath): \(self.bannerHeight.constant)")
else
self.bannerView.isHidden = true
self.bannerHeight.constant = 1
completion(self.bannerHeight.constant)
else
bannerView.isHidden = true
bannerHeight.constant = 1
completion(bannerHeight.constant)
// code from delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
let width = self.view.bounds.width
let height = bannersHeight[indexPath.row] + contentsHeight[indexPath.row]
+ 1 // sticker
+ 11 // banner top
printD("indexPath: \(indexPath): \(height)")
return CGSize(width: width, height: height)
【问题讨论】:
【参考方案1】:这不是错误。这就是为给定索引路径重新加载单元格的方式。如果你只想更新布局也可以试试
[self.collectionView.collectionViewLayout invalidateLayout]
而不是
self.collectionView.reloadItems(at: [indexPath])
然后在委托方法中返回正确的大小。
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
return //whatever size that you want to return.
我还强烈建议您缓存您的图像大小,以便您下次可以使用它,而不是过度下载/计算......
【讨论】:
谢谢。顺便说一句,我听说您建议我缓存调整大小的图像而不是原始图像,并从缓存图像中获取高度。但似乎我从 SDImageCache 获得了具有错误比例属性的图像。我将针对该问题打开另一个问题。 如果您调用使布局无效,这将使整个布局无效。如果有人只想重新布局特定单元格怎么办?以上是关于UICollectionView 将在调用“reloadItems”方法时重新创建单元格的主要内容,如果未能解决你的问题,请参考以下文章
为啥 std::rel_ops::operators 在 C++20 中会被弃用?
调用 didHighlightItemAtIndexPath 而不调用 UICollectionView 的 didSelectItemAtIndexPath
设备旋转后的 UICollectionView contentOffset
UICollectionView *Assertion Failure* 未在 UICollectionViewCell 上应用属性