具有异步图像加载的自调整 UICollectionView 单元格

Posted

技术标签:

【中文标题】具有异步图像加载的自调整 UICollectionView 单元格【英文标题】:Self-sizing UICollectionView cells with async image loading 【发布时间】:2019-03-20 11:28:20 【问题描述】:

我有一个水平的UICollectionView,我在其中显示异步加载的图像。单元格的宽度应该适合图像。

在我的视图控制器的viewDidLoad 中,我设置了估计的单元格大小:

(collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.estimatedItemSize = CGSize(width: 400, height: 400)

cellForItem,我使用Kingfisher启动下载任务:

cell.imageView.kf.setImage(with: url)  (_, _, _, _) in 
    cell.layoutSubviews()

在我的单元格中,layoutSubviews 方法中有以下代码:

// 326 is the image view's height
// .aspectRatio is a custom extension that returns: size.width / size.height
imageViewWidthConstraint.constant = 326 * image.aspectRatio
layoutIfNeeded()

在情节提要中,我已正确设置布局约束,以便单元格宽度尊重imageViewWidthConstraint

以下是运行我的应用时的结果:

如您所见,单元格的宽度为 400,尽管已加载图像并更新了布局。因此,图像会被拉伸以填充图像视图。 当我向右滚动然后返回时,单元格将从集合视图中删除并重新加载,现在布局正确:

在滚动时,单元格会调整它们的宽度,有时会调整到正确的宽度,有时会调整到错误的宽度。

我在这里做错了什么?

【问题讨论】:

嗨,我刚刚用 tableView 实现了同样的东西。这是Link。我必须保持宽度不变并根据图像尺寸动态调整高度。看看代码以获得一个想法。基本上,您应该在SizeForItemAt IndexPath 返回大小,并且您的图像应该固定到集合视图。 @AwaisFayyaz 您如何为收藏视图执行此操作? 【参考方案1】:

由于您的图片是异步传入的,因此加载可能需要一些时间。只有加载它们后,您才能真正知道图像的大小或比例。这意味着对于加载的每个图像,您都需要“重新加载”您的布局。从简短的搜索来看,this 看起来很有希望。

至少这样你可能会得到一些动画,否则你的单元格会在图像开始加载时不断跳跃。

无论如何,我建议您避免这种情况。如果我可以假设;您正在从服务器获取一些数据,您使用提供的 URL 从中下载图像并将它们显示在集合视图上。最好的方法(如果可能的话)是请求扩展 API,以便您也接收图像的尺寸。所以不是


    id: 1,
    image: "https://..."

你可以有


    id: 1,
    image: 
        url: "https://...",
        width: 100,
        height: 100
     

您现在可以在下载图像之前使用这些值生成宽高比宽度/高度。

除此之外,我真的没有看到任何好的解决方案让整个事情看起来不错(不跳来跳去)。

【讨论】:

图像确实需要一秒钟才能加载,但布局没有更新...感谢在 API 响应中传递宽度和高度参数的建议,我可能会这样做它应该会产生最佳的视觉效果。 不过,我不会接受你的回答,因为从技术上讲,它不能回答我的问题? 也许有一天有人会提出解决方案。改为thanks @LinusGeffarth "但是布局没有更新";该部分应由我提供的链接修复。但问题是您需要将该代码放入您正在使用的工具的某个回调中,以便在图像视图上设置新图像... 确实,我之前有过reloadItems(at:),在每张图片下载完成后我都会调用它。问题是当滚动 b/c 新单元格加载时它会跳来跳去...... @LinusGeffarth 它也可以启用分页。想象一下,您将创建一个对单个页面的请求,并获得 200 个项目,它们都具有一个图像。此时,您还不会调用完成块,而是为每个图像创建 200 个并行 HEAD 请求。一旦你得到 200 个大小,你就可以将大小注入到你的有效负载中,然后调用完成。所以基本上你会保留完全相同的系统,但等待那些额外的数据。

以上是关于具有异步图像加载的自调整 UICollectionView 单元格的主要内容,如果未能解决你的问题,请参考以下文章

在 UITableViewCells 中显示之前调整图像大小和裁剪图像

如何调整 UIImageView 的大小并强制重新布局父 UITableViewCell

下载图像时 UITableViewCell 高度调整大小

下载内部图像后调整 UICollectionView 单元格的大小

在列表视图中加载图像时加载错误的图像

具有 uitableviewdiffabledatasource 的自调整单元格