Swift如何提高UICollectionView获取照片缩略图显示效率
How to improve efficiency of getting thumbnails of photos and displaying them in UICollectionView in Swift
我正在 Swift 中编写一个简单的自定义照片选择器。看看 GIF,您会发现它有什么问题:
当我点击状态栏 quickly
滚动到顶部时,由于单元格被重复使用并且重新生成缩略图需要很短的时间,因此图片都混淆了,因此,这发生。我想知道无论我滚动多快,我如何解决这个问题?我的这个选择器代码是:
func getThumbnail(asset: PHAsset, targetSize: CGSize, onComplete: @escaping (UIImage?, [AnyHashable: Any]?) -> ()) {
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
option.resizeMode = .fast
option.isNetworkAccessAllowed = true
manager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: option) { (thumbnail, info) in
onComplete(thumbnail, info)
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = ...
let asset = photos[indexPath.row] // "photos" is an array of all photos in library
// and its type is "[PHAsset]"
let photoSize = collectionView.frame.width / 3
getThumbnail(asset: asset, targetSize: CGSize(width: photoSize, height: photoSize, onComplete: { (image, _) -> Void in
(cell.viewWithTag(1) as! UIImageView).image = image
// A cell has a UIImageView, whose size is equal to cell size,
// whose tag = 1
}))
return cell
}
在你的 cellForItemAt 的第一行放
cell.imageView.image = 无
这将防止出列的单元重新使用图像,从而减少闪烁。如果图像在内存中,它会立即被替换,没问题。
仅仅因为您正在使用缓存并不意味着您所有的图像当前都在内存中。当您将图像读入内存时会发生闪烁,尤其是通过网络以及当您需要调整单元格大小时(尽管您的单元格看起来大小相同)。
您可能需要考虑在滚动结束时只更新一次视图,而不是针对每个单元格。
如果需要,您可以检查 scrollViewWillBeginDragging 以关闭更新和 scrollViewDidEndDecelerating 以执行更新。
我在 UITableView
中遇到了同样的问题。当我使用 AlamofireImage 时
af_setImage(withURL: URL(string: pictureUrl))
然后我使用 AlamofireImage 的
af_setImage(withURL: URL(string: pictureUrl)!, placeholderImage: UIImage(named: "YourPlaceholder.png"))
使用占位符图像解决问题。
来自您的代码:
let cell = ...
此时,您还没有图像,因此您应该将图像视图的图像设置为 nil
或占位符图像:
let cell = ...
(cell.viewWithTag(1) as! UIImageView).image = placeholderImage
也来自您的代码:
getThumbnail(asset: asset, targetSize: CGSize(width: photoSize, height: photoSize, onComplete: { (image, _) -> Void in
(cell.viewWithTag(1) as! UIImageView).image = image
此时,cell
可能不再是原始索引路径(因此 image
)的正确单元格。原始索引路径可能没有单元格,或者索引路径可能有不同的单元格。您需要向集合视图询问正确的单元格:
getThumbnail(asset: asset, targetSize: CGSize(width: photoSize, height: photoSize, onComplete: { (image, _) -> Void in
guard let cell = collectionView.cellForItem(at: indexPath) else { return }
(cell.viewWithTag(1) as! UIImageView).image = image
我正在 Swift 中编写一个简单的自定义照片选择器。看看 GIF,您会发现它有什么问题:
当我点击状态栏 quickly
滚动到顶部时,由于单元格被重复使用并且重新生成缩略图需要很短的时间,因此图片都混淆了,因此,这发生。我想知道无论我滚动多快,我如何解决这个问题?我的这个选择器代码是:
func getThumbnail(asset: PHAsset, targetSize: CGSize, onComplete: @escaping (UIImage?, [AnyHashable: Any]?) -> ()) {
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
option.resizeMode = .fast
option.isNetworkAccessAllowed = true
manager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: option) { (thumbnail, info) in
onComplete(thumbnail, info)
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = ...
let asset = photos[indexPath.row] // "photos" is an array of all photos in library
// and its type is "[PHAsset]"
let photoSize = collectionView.frame.width / 3
getThumbnail(asset: asset, targetSize: CGSize(width: photoSize, height: photoSize, onComplete: { (image, _) -> Void in
(cell.viewWithTag(1) as! UIImageView).image = image
// A cell has a UIImageView, whose size is equal to cell size,
// whose tag = 1
}))
return cell
}
在你的 cellForItemAt 的第一行放
cell.imageView.image = 无
这将防止出列的单元重新使用图像,从而减少闪烁。如果图像在内存中,它会立即被替换,没问题。
仅仅因为您正在使用缓存并不意味着您所有的图像当前都在内存中。当您将图像读入内存时会发生闪烁,尤其是通过网络以及当您需要调整单元格大小时(尽管您的单元格看起来大小相同)。
您可能需要考虑在滚动结束时只更新一次视图,而不是针对每个单元格。
如果需要,您可以检查 scrollViewWillBeginDragging 以关闭更新和 scrollViewDidEndDecelerating 以执行更新。
我在 UITableView
中遇到了同样的问题。当我使用 AlamofireImage 时
af_setImage(withURL: URL(string: pictureUrl))
然后我使用 AlamofireImage 的
af_setImage(withURL: URL(string: pictureUrl)!, placeholderImage: UIImage(named: "YourPlaceholder.png"))
使用占位符图像解决问题。
来自您的代码:
let cell = ...
此时,您还没有图像,因此您应该将图像视图的图像设置为 nil
或占位符图像:
let cell = ...
(cell.viewWithTag(1) as! UIImageView).image = placeholderImage
也来自您的代码:
getThumbnail(asset: asset, targetSize: CGSize(width: photoSize, height: photoSize, onComplete: { (image, _) -> Void in
(cell.viewWithTag(1) as! UIImageView).image = image
此时,cell
可能不再是原始索引路径(因此 image
)的正确单元格。原始索引路径可能没有单元格,或者索引路径可能有不同的单元格。您需要向集合视图询问正确的单元格:
getThumbnail(asset: asset, targetSize: CGSize(width: photoSize, height: photoSize, onComplete: { (image, _) -> Void in
guard let cell = collectionView.cellForItem(at: indexPath) else { return }
(cell.viewWithTag(1) as! UIImageView).image = image