Swift中Kingfisher下载失败时隐藏UIImageView并更新UICollectionViewCell尺寸
问题描述
实现Kingfisher下载图片失败时,隐藏UICollectionViewCell中的UIImageView,同时自动更新对应单元格的尺寸。
现有代码
setData方法(cellForItem中调用)
func setData(with data: Article?, indexPath: IndexPath) { guard let data = data else { return } if let imageUrl = data.urlToImage, imageUrl.isValidURL, let url = URL(string: imageUrl.addingPercentEncoding) { self.newsImageView.kf.setImage(with: url, options: [.transition(.fade(0.3))]) { [weak self] result in guard let self = self else { return } switch result { case .success(_): self.newsImageView.isHidden = false case .failure(let error): self.newsImageView.isHidden = true // 仅隐藏图片无法满足需求,需要同步更新单元格尺寸 } } } else { self.newsImageView.isHidden = true } }
collectionView(_:cellForItemAt:)代理实现
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let homeCell = collectionView.dequeueReusableCell(withReuseIdentifier: HomeCollectionViewCell.identifier, for: indexPath) as? HomeCollectionViewCell, let article = viewModel.getArticle(at: indexPath) else { let emptyCell = collectionView.dequeueReusableCell(withReuseIdentifier: EmptyArticlesCollectionViewCell.identifier, for: indexPath) return emptyCell } homeCell.configure(with: article, indexPath: indexPath) return homeCell }
HomeCollectionViewCell相关实现
class HomeCollectionViewCell: UICollectionViewCell { @IBOutlet weak var homeCollectionViewCellComponent: HomeCollectionViewCellComponent! . . . func configure(with data: Article, indexPath: IndexPath) { homeCollectionViewCellComponent.setData(with: data, indexPath: indexPath) } override func prepareForReuse() { homeCollectionViewCellComponent.prepareForReuse() } }
实现方案
按以下步骤调整即可:
- 先在数据层加状态标记,不要把图片加载成功/失败的状态仅存在cell内部。给
Article模型新增布尔属性hasValidImage,初始化时如果存在合法图片URL就默认设为true,无有效URL则设为false。 - 调整Kingfisher加载回调逻辑:加载成功时将对应位置数据的
hasValidImage设为true,加载失败时设为false,不要只修改cell的isHidden属性就结束。 - 配置自适应约束:把
newsImageView的高度约束拖成属性,当hasValidImage为true时使用正常图片高度(比如按屏宽16:9比例计算),为false时将高度约束值改为0;其余控件的垂直约束要依次衔接,图片高度为0时整个cell的内容高度会自动收缩。 - 在
collectionView(_:layout:sizeForItemAt:)代理方法中,直接读取对应位置Article模型的hasValidImage状态计算返回尺寸,不要从已加载的cell中取状态计算,避免复用错位。 - 图片加载回调中更新完模型状态后,在主线程调用
performBatchUpdates刷新对应位置的cell即可,不要全量调用reloadData(),避免列表闪烁:
DispatchQueue.main.async { collectionView.performBatchUpdates({ collectionView.reloadItems(at: [indexPath]) }) }
- 补充复用逻辑:在
prepareForReuse方法里把newsImageView的高度约束重置为默认值,同时重置图片的显示状态,避免cell复用时出现布局错乱。
注意:不要在cell内部持有indexPath做逻辑判断,cell复用过程中indexPath会动态变化,很容易读错对应数据,所有和单元格相关的状态统一从ViewModel/Model层读取是最稳妥的方案。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

