预加载下一个(当前不可见)单元格 UICollectionView

Posted

技术标签:

【中文标题】预加载下一个(当前不可见)单元格 UICollectionView【英文标题】:Preload next (currently invisible) cell UICollectionView 【发布时间】:2015-10-13 22:10:54 【问题描述】:

我正在使用 UICollectionView 并且当前有全屏单元格,当我滑动到下一个单元格时,图像需要一点时间才能加载到单元格中(因为它们是高分辨率的)。我已经在使用 PHCachingImageManager 预先缓存图像,并且在我加载单元格之前它已经被缓存,但是仅仅将图像加载到 imageView 需要一个明显的时间火花。我想知道是否有办法在它到达 cellForItemAtIndexPath 之前预加载不可见的下一个单元格?

有什么想法吗?

【问题讨论】:

【参考方案1】:

加载已经从 PHCachingImageManager 缓存的图像显然需要一些时间,这是我延迟的原因。我创建了一个测试函数,在设置当前单元格时将下一个图像(并且也会添加上一个图像)保存在一个属性中,并且我的闪烁不再存在。清理完后我会发布工作示例...

更新: 所以我创建了一个 _images NSMutableDictionary 来存储已经加载的图像并使用这个函数填充它

- (void)startCachingSurroundingImages:(NSInteger)index 
CGSize targetSize = PHImageManagerMaximumSize;
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
[options setNetworkAccessAllowed:YES];
[options setDeliveryMode:PHImageRequestOptionsDeliveryModeHighQualityFormat];

if (index < _imagesArray.count - 1 && ![_images objectForKey:[NSIndexPath indexPathForItem:0 inSection:index+1]]) 
    NSDictionary *assetDictionary = [_imagesArray objectAtIndex:index + 1];
    NSString *assetRefID = [assetDictionary objectForKey:@"asset_id"];

    PHFetchResult *assetFetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[assetRefID] options:[PHFetchOptions new]];
    PHAsset *asset = [assetFetchResult firstObject];



    [photoManager requestImageForAsset:asset targetSize:targetSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) 
        if (result) 
            [_images setObject:result forKey:[NSIndexPath indexPathForItem:0 inSection:index+1]];
        
    ];


if (index - 1 >= 0 && ![_images objectForKey:[NSIndexPath indexPathForItem:0 inSection:index-1]]) 
    NSDictionary *leftAssetDictionary = [_imagesArray objectAtIndex:index - 1];
    NSString *leftAssetRefID = [leftAssetDictionary objectForKey:@"asset_id"];

    PHFetchResult *leftAssetFetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[leftAssetRefID] options:[PHFetchOptions new]];
    PHAsset *leftAsset = [leftAssetFetchResult firstObject];

    [photoManager requestImageForAsset:leftAsset targetSize:targetSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) 
        if (result) 
            [_images setObject:result forKey:[NSIndexPath indexPathForItem:0 inSection:index-1]];
        
    ];
  

我在 cellForItemAtIndexPath 中这样调用...

[self startCachingSurroundingImages:indexPath.section];

仍然在 cellForItemAtIndexPath 中,我像这样加载图像...

if ([_images objectForKey:indexPath]) 
    cell.imageView.image = [_images objectForKey:indexPath];
    [photoCell.activityIndicator setHidden:YES];
 else 
    photoCell.tag = (int)[photoManager requestImageForAsset:asset targetSize:targetSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) 
        PhotoCell *photoCell = (PhotoCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
        if (photoCell && result) 
            photoCell.imageView.image = result;
            [photoCell.activityIndicator setHidden:YES];
         else 
            NSLog(@"BAD IMAGE!!! %@", info);
            [photoCell.activityIndicator setHidden:NO];
        
    ];

然后在 didReceiveMemoryWarning 我清理了一下...

- (void)didReceiveMemoryWarning 
  NSArray *allKeys = [_images allKeys];
  for (int i = 0; i < _images.count; i++) 
    NSIndexPath *path = [allKeys objectAtIndex:i];
    if (path.section != _lastIndex && path.section != _lastIndex - 1 && path.section != _lastIndex + 1) 
        [_images removeObjectForKey:path];
    
  
  // Though one could just as easily do this 
  // [_images removeAllObjects];

它不漂亮,但它有效。

【讨论】:

以上是关于预加载下一个(当前不可见)单元格 UICollectionView的主要内容,如果未能解决你的问题,请参考以下文章

通过预加载单元格提高 UITableView 性能

重新加载 UITableView 数据而不是可见单元格

从另一个视图控制器添加单元格时 UITableViewCell 的内容不可见

IGListKit:获取当前可见的单元格索引

UICollectionView indexPathsForVisibleItems 不更新新的可见单元格

ios reloadData 仅重新加载不可见的单元格