【问题标题】:Smooth Scrolling with 500+ images使用 500 多张图像平滑滚动
【发布时间】:2013-08-30 17:31:26
【问题描述】:

超级编辑:

好的,经过几次不同的修改,我有一个更明确的问题。基本上我正在努力使用 NSCache。我有一个集合视图,如下所示,我希望能够最大程度地减少图像的滚动延迟,我大部分时间都在这样做。困难的部分是移动到全尺寸图像。它在另一个视图中,我希望过渡到全尺寸照片,就像 Apple 使用他们的照片应用程序所做的那样。

似乎 Apple 正在缓存图像并以不同的方式访问它们。我发现我需要加载原始缩略图,然后在下载全尺寸图像时我可以替换它。但我不知道该怎么做。

到目前为止,我拥有的是:

UICollection 视图

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    self.myCache = [[NSCache alloc] init];

}

//Reusable cell structure
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    //cell
    CoverPhotoCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"CoverImgCell" forIndexPath:indexPath];
    cell.backgroundColor = [UIColor blackColor];
    cell.clipsToBounds = YES;
    cell.opaque = YES;
    cell.layer.shouldRasterize = YES;
    cell.layer.rasterizationScale = [UIScreen mainScreen].scale;

    Media *object = [[Media alloc] init];
    object = [self.photoListArray objectAtIndex:indexPath.item];

    //Remove old cell
    for (UIView *subview in [cell subviews]){
        if (subview.tag != 0 )
        {
            [subview removeFromSuperview];
        }
    }

    //UIImage
    UIImage *thumbImg = [_myCache objectForKey:object.url];

    if (thumbImg) {

        cell.imageView.image = thumbImg;
    }
    else {

        cell.imageView.image = nil;

        UIImage *thumbImg = [[UIImage alloc] initWithCGImage:[object.asset aspectRatioThumbnail]];

        dispatch_async(dispatch_get_main_queue(), ^{
            cell.imageView.image = thumbImg;
        });

        [_myCache setObject:thumbImg forKey:object.url];

    }

    //thumbnail
    cell.imageView.tag = indexPath.row + 1;

    cell.imageView.layer.borderWidth = 5;
    cell.imageView.layer.borderColor = [UIColor whiteColor].CGColor;
    cell.imageView.contentMode = UIViewContentModeScaleAspectFit;

    cell.imageView.frame = CGRectMake(0, 0, 125, 125);

    return cell;
}

//User taps image
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"PhotoSegue"]) {
        DetailPageController *controller = segue.destinationViewController;

        NSIndexPath *selectedIndex = [self.collectionView indexPathsForSelectedItems][0];

        controller.initialIndex = (NSUInteger)selectedIndex.item;

        controller.photos = self.photoListArray;

    }
}

这就是我的 NSCache 代码,然后我使用 segue 到显示全分辨率照片的全视图控制器。如何先加载缩略图,然后再加载全尺寸图像。

还有关于苹果如何如此快速地加载图像的想法吗?他们是否使用不同的缓存方式?还是我做错了什么。

精致编辑:


有人可以发布或至少将我指向一些示例代码,当用户快速滚动时我会显示缩略图并在他们放慢速度时加载实际图像,类似于我猜苹果电影预告片应用程序。

【问题讨论】:

  • “困难的部分是移动到全尺寸图像。它在另一个视图中,我希望过渡到全尺寸照片,就像 Apple 使用他们的照片应用程序所做的那样” i> - 你有一个特定的指标吗? “似乎Apple正在缓存图像并以不同方式访问它们。我发现我需要加载原始缩略图,然后在下载全尺寸图像时我可以替换它。但我不确定如何做到这一点。” 你能澄清一下吗?他们如何“以不同的方式”访问它?具体是什么你不确定?

标签: ios objective-c uicollectionview


【解决方案1】:

一个完整的代码答案对于 SO 来说太过分了。所以我尝试描述基础知识:

您应该创建自己的图像缓存。使用页面滚动视图,最多可以看到两个图像。在启用分页的滚动视图中查看照片时,图像缓存必须至少保存三张完整尺寸的图像。

缓存的工作原理如下:

假设您有一个图像列表,可以通过与“相册查看器”的滚动视图中的位置相对应的索引来访问它。

当前索引,(异步)将图像加载到索引1、索引和索引+1的缓存中,除非该图像已经存在于缓存中或索引超出范围。

当用户开始滚动时,下一张图片将变得可见。

当用户向前滚动并滚动了半页时,当前索引会增加一。此时,可以看到两个图像 - 每个图像的一半。现在,当索引更改时,您将图像放在当前索引 2 处,并在当前索引 + 1 处加载下一张图像。

当用户向后滚动时,索引会减一。你抛出 at index+2 并为当前 index-1 加载相应的图像。

您可以通过添加与上述完全相同的缩略图视图缓存来改进该方案,但使用范围更广,例如提前加载 20 张图像。当完整大小的图像尚未加载时,将缩略图用作“占位符”(注意:一切都应是异步的)。

如果用户“快速”滚动,则不要加载全尺寸图像,只需等待速度降低到一定数量即可。您可以通过一些努力来确定滚动的速度。

如果用户滚动得非常快,那么即使是缩略图在应该显示的时候也不可用。然后,求助于静态占位符图像。 (还要注意不要用拇指图像覆盖全尺寸图像)。

【讨论】:

  • 也许我描述得不好,我已经有全屏版本了,它的缩略图让我很难。
  • 例如照片应用可以很好地滚动大型收藏。
  • 你应该仔细阅读。你不应该做的是在单元格可见时加载图像 - 那么已经太晚了。相反,您只需要显示准备好的图像,并将 next 视图异步加载到缓存中。您的方法不可扩展,而且可能会卡顿。
  • 是否有特定的方法可以让我预加载图像?
  • 我会说,当您的 UICollectionView 请求索引 i 处的项目时,您会在索引 i+1 处预加载图像。
【解决方案2】:

我会用AFNetworking 加载图像。

你可以使用下面的

[imageView setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]];

您可以将占位符加载为缩略图,加载后它将被其他图像替换。

http://cocoadocs.org/docsets/AFNetworking/1.3.1/Categories/UIImageView+AFNetworking.html

【讨论】:

  • 我喜欢你的想法,但我正在从资源库中获取我的照片。
  • 好的,所以我将使用类似的方法来完成此操作。首先使用占位符图像加载相关的图像视图。然后使用完成块将图像传回并使用收到的新图像更新图像视图图像来触发您的后台线程(如果需要)
猜你喜欢
  • 2012-08-25
  • 2012-03-08
  • 1970-01-01
  • 2012-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-12
  • 1970-01-01
相关资源
最近更新 更多