【问题标题】:Dequeue cells more than default UICollectionView dequeued cells出列单元格比默认 UICollectionView 出列单元格多
【发布时间】:2021-09-25 01:15:09
【问题描述】:

有没有办法让比默认 UICollectionView 出列单元格更多的单元格出列?例如,在下面的图片中,UICollectionView 出列显示单元格,一个前一个后一个。有没有办法让这三个以上的单元格出列?func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) { print("Prefetch: \(indexPaths)") }

之后只给我一个索引路径。我需要的是在显示单元格之后和之前创建四个或五个单元格,以便在显示单元格之前实现我的功能。

【问题讨论】:

  • 在需要时调用 Dequeue:~当需要显示单元格时。这避免了不必要的加载(这意味着更少的 CPU 使用,更快,更少的电池等)。虽然,通过扩展您的 collectionView 的 contentSize,您可能能够强制该出队。因为如果我没记错的话,实际上是当单元格进入 contentSize 部分时。然后需要更多技巧来避免不显示 collectionView 内容的顶部/底部部分。
  • @Paulw11 正如我已经说过的,预取给了我一个索引路径。我需要的是能够访问超过一个索引路径的单元格,比如四个或五个
  • @OmidKia:为什么你需要那个?
  • @MartinR 我的每个单元格都包含一个用于播放视频的 AVPlayer 实例。我需要一个用 AVPlayer 完全实例化的单元格,以便在可见时准备和播放。
  • @Larme 我想增加 contentSize 会导致在我的 collectionView 底部创建不需要的空白,我认为这不是解决这个问题的干净方法

标签: ios swift uicollectionview


【解决方案1】:

official Apple sample code 显示了一种您可能会发现有用的技术。无需依赖UICollectionView 来接收回调并根据需要加载数据,您可以观察滚动并根据contentOffset 的值,您将知道需要多少前瞻性。

在此处复制粘贴相关部分,以防将来的读者无法使用链接。所有这些都存在于UICollectionViewController 子类中——它可以适应任何UIScrollView

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    // This is your trigger point
    updateCachedAssets()
}
var fetchResult: PHFetchResult<PHAsset>!
fileprivate let imageManager = PHCachingImageManager()
fileprivate let thumbnailSize: CGSize = CGSize(width: 100, height: 100)
fileprivate var previousPreheatRect = CGRect.zero
fileprivate func updateCachedAssets() {
    // Update only if the view is visible.
    guard isViewLoaded && view.window != nil else { return }
    
    // The window you prepare ahead of time is twice the height of the visible rect.
    let visibleRect = CGRect(origin: collectionView!.contentOffset, size: collectionView!.bounds.size)
    let preheatRect = visibleRect.insetBy(dx: 0, dy: -0.5 * visibleRect.height)
        
    // Update only if the visible area is significantly different from the last preheated area.
    let delta = abs(preheatRect.midY - previousPreheatRect.midY)
    guard delta > view.bounds.height / 3 else { return }
    
    // Compute the assets to start and stop caching.
    let (addedRects, removedRects) = differencesBetweenRects(previousPreheatRect, preheatRect)
    let addedAssets = addedRects
        .flatMap { rect in collectionView!.indexPathsForElements(in: rect) }
        .map { indexPath in fetchResult.object(at: indexPath.item) }
    let removedAssets = removedRects
        .flatMap { rect in collectionView!.indexPathsForElements(in: rect) }
        .map { indexPath in fetchResult.object(at: indexPath.item) }
        
    // Update the assets the PHCachingImageManager is caching.
    imageManager.startCachingImages(for: addedAssets,
                                    targetSize: thumbnailSize, contentMode: .aspectFill, options: nil)
    imageManager.stopCachingImages(for: removedAssets,
                                   targetSize: thumbnailSize, contentMode: .aspectFill, options: nil)
    // Store the computed rectangle for future comparison.
    previousPreheatRect = preheatRect
}
fileprivate func differencesBetweenRects(_ old: CGRect, _ new: CGRect) -> (added: [CGRect], removed: [CGRect]) {
    if old.intersects(new) {
        var added = [CGRect]()
        if new.maxY > old.maxY {
            added += [CGRect(x: new.origin.x, y: old.maxY,
                             width: new.width, height: new.maxY - old.maxY)]
        }
        if old.minY > new.minY {
            added += [CGRect(x: new.origin.x, y: new.minY,
                             width: new.width, height: old.minY - new.minY)]
        }
        var removed = [CGRect]()
        if new.maxY < old.maxY {
            removed += [CGRect(x: new.origin.x, y: new.maxY,
                               width: new.width, height: old.maxY - new.maxY)]
        }
        if old.minY < new.minY {
            removed += [CGRect(x: new.origin.x, y: old.minY,
                               width: new.width, height: new.minY - old.minY)]
        }
        return (added, removed)
    } else {
        return ([new], [old])
    }
}

注意事项

  1. 该代码已有多年历史,您需要根据自己的要求对其进行调整。
  2. 您可以调整 preheatRect 计算以满足您的需求。
// The window you prepare ahead of time is twice the height of the visible rect.
let visibleRect = CGRect(origin: collectionView!.contentOffset, size: collectionView!.bounds.size)
let preheatRect = visibleRect.insetBy(dx: 0, dy: -0.5 * visibleRect.height)
  1. 示例实现此preheatRect 逻辑以预加载PHAsset 缩略图。您需要将您的数据源调整为类似的样式并开始/停止加载您的资源。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多