【问题标题】:On iOS, how to make a cell.imageView refresh its content?在 iOS 上,如何让 cell.imageView 刷新其内容?
【发布时间】:2012-08-31 05:29:32
【问题描述】:

我正在tableView:cellForRowAtIndexPath 中尝试通过调用来设置图像

[self downloadImage:urlString andSetIntoCellImageView:cell]

downloadImage 中,它会调用NSURLConnection:sendAsynchronousRequest(仅限iOS 5 及更高版本),并在完成块中,使用设置图像

cell.imageView.image = [UIImage imageWithData:data];   // data is downloaded data

如果在tableView:cellForRowAtIndexPath 中,imageView 填充了一个虚拟占位符图像,它就可以工作——我想知道新图像是如何刷新的,是 setNeedsDisplay 重新绘制吗?但是如果我不设置占位符图像,那么新图像根本不会显示。我想知道有什么机制可以让它显示图像?

如果我使用

[cell.imageView setNeedsDisplay]

[cell setNeedsDisplay];

在完成块中,它不起作用,如果我使用

[self.table reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                            withRowAnimation:UITableViewRowAnimationAutomatic];

在完成块中通过使downloadImage接受indexPath,它将再次调用tableView:cellForRowAtIndexPath,并导致无限循环。所以看来我需要使用一些哈希表来记住图像是否已经在哈希表中:如果没有,请调用downloadImage,如果在哈希表中,只需使用它,这样就不会无限循环。

但是有没有一种简单的方法可以让图片显示出来?设置占位符图像有效,但如果我们不这样做 - 占位符通过什么机制导致图像刷新?

【问题讨论】:

  • 所以cell.imageView.image = [UIImage imageWithData:data] 只要在tableView:cellForRowAtIndexPath: 方法中的单元格中设置了占位符图像就可以工作,但是如果您不提供占位符,那么同样的技术不起作用吗?您介意发布您是如何设置占位符图像的吗?
  • @CarlVeazey 这是正确的。当然,我使用 cell.imageView.image = [UIImage imageNamed:@"pic0.png"]; 设置了占位符

标签: iphone ios uitableview sendasynchronousrequest


【解决方案1】:

当调用UITableViewCell-layoutSubviews方法时,如果其imageViewimage属性为nil,则imageView被赋予(0,0,0,0)的框架。此外,-layoutSubviews 仅在某些情况下被调用:当单元格即将变为可见时以及当它被选中时。不是在正常滚动期间。所以你看到的是,将tableView:cellForRowAtIndexPath: 中的占位符设置为cell.imageView 的大小为非零大小,随后图像的更改将是可见的。

我通过在完成处理程序中调用 [cell setNeedsLayout] 解决了这个问题,如下所示:

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:MY_IMAGE_URL]];
[NSURLConnection sendAsynchronousRequest:request
                                   queue:self.operationQueue
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                                UIImage *image = [UIImage imageWithData:data];
                                                cell.imageView.image = image;
                                                [cell setNeedsLayout];
                                            }];

我发现完成块发生在后台,因此需要在主线程上执行我的 UI 工作。当然这个解决方案不会考虑细胞重用等等,但至少解决了为什么细胞的图像不会出现:)

希望这会有所帮助!

【讨论】:

  • 但是,为什么setNeedsDisplay 不起作用?另一件事是,如果我们在tableView:cellForRowAtIndexPath 中重用一个单元格,我们实际上需要执行cell.imageView.image = nil 否则该单元格将在加载正确图像之前显示“旧”图像一段时间并替换它
  • setNeedsDisplay 只调用drawRect 被调用,我认为,这将绘制那里的元素,但不会调整大小或重新定位任何东西。是的,必须有额外的工作来处理单元格的重用、缓存图像等等。
  • 另一个观察结果是,如果我们实际上将UIActivityIndicatorView 添加到图像将出现的位置,我们可能希望使用一个空的、可能是透明的图像,以便可以将UIActivityIndicatorView 添加到图像视图。否则,它不会显示。 (使用[[imageView viewWithTag:100] removeFromSuperview]; 在完成块中删除指示符
  • 但如果我先设置imageView.frame = CGRectMake(0,0, 300,300); 然后调用[cell setNeedsDisplay];[cell.imageView setNeedsDisplay];,图像仍然不会显示
  • 这可能是因为 layoutSubviews 设置了它
【解决方案2】:

这不能直接回答您的问题,但解决您的问题的一个简单解决方法是在您的 cellForRowAtIndexPath: 中使用 SDWebImage。他们的 README 页面上的示例完全符合您的要求。

【讨论】:

  • 是的,我收集了这 4 个:SDWebImage、AFNetworking、TTImageView(来自 Three20)和 ASIHTTPRequest(由 Rob Napier 推荐)...所以我会一一尝试...但是对于现在,我只是在试验 iOS 5 的内置方法
猜你喜欢
  • 1970-01-01
  • 2013-04-10
  • 2012-12-17
  • 2021-04-08
  • 2021-09-29
  • 2010-10-22
  • 1970-01-01
  • 2019-02-05
  • 2016-02-21
相关资源
最近更新 更多