Ios 如何在自定义UICollectionViewCell上正确加载图像?
我整个下午都在这里,我想不出来,所以你的帮助太棒了!我有一个自定义的UICollectionViewCell,我用动态创建的图像填充它。图像的路径存储在Parse中,查询完成后,我调用[self.collectionView reloadData] 在我的cellForItemAtIndexPath中,我有以下代码:Ios 如何在自定义UICollectionViewCell上正确加载图像?,ios,objective-c,iphone,uicollectionview,uicollectionviewcell,Ios,Objective C,Iphone,Uicollectionview,Uicollectionviewcell,我整个下午都在这里,我想不出来,所以你的帮助太棒了!我有一个自定义的UICollectionViewCell,我用动态创建的图像填充它。图像的路径存储在Parse中,查询完成后,我调用[self.collectionView reloadData] 在我的cellForItemAtIndexPath中,我有以下代码: - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtI
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MovieCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
// Configure the cell
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"original_title" ascending:YES];
[self.moviesforWatchlist sortUsingDescriptors:[NSArray arrayWithObjects:sort, nil]];
cell.userInteractionEnabled = YES;
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[cell addSubview:spinner];
NSDictionary *movie = self.moviesforWatchlist[indexPath.row];
NSString *moviePosterPath = movie[@"poster_path"];
NSString *posterURL = [NSString stringWithFormat:@"http://image.tmdb.org/t/p/w342%@", moviePosterPath];
NSURL *posterImage = [NSURL URLWithString:posterURL];
UIImage *cachedImage = [self.imageCache objectForKey:posterImage];
if (cachedImage) {
cell.imageView.image = cachedImage;
}
else if (cell.imageView.image == nil) {
cell.imageView.image = [UIImage imageNamed:@"default_collectionviewcell.jpeg"];
dispatch_queue_t downloadQueue = dispatch_queue_create("get image data", NULL);
dispatch_async(downloadQueue, ^{
[spinner startAnimating];
NSData *imageData = [NSData dataWithContentsOfURL:posterImage];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
MovieCollectionViewCell *updateCell = (id)[collectionView cellForItemAtIndexPath:indexPath];
if (updateCell) {
updateCell.imageView.image = image;
[updateCell reloadInputViews];
[self.collectionView reloadItemsAtIndexPaths:[self.collectionView indexPathsForVisibleItems]];
}
});
[self.imageCache setObject:image forKey:posterImage];
});
}
[self.collectionView reloadItemsAtIndexPaths:[self.collectionView indexPathsForVisibleItems]];
return cell;
}
我这样调用查询方法:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self getWatchlistData];
[self.collectionView reloadData];
}
这会导致图像闪烁,直到图像加载到UICollectionViewCells。我希望在我的collectionviewcell中显示的图像按字母顺序排列,因此我正在对保存路径的数组进行排序,在cellforitemsatindexpath中,这是导致图像闪烁的原因吗?还是别的什么?非常感谢你的帮助 尝试使用
我会改变很多事情: 我不会在CellForItemSatineXPath中对数组进行排序。当每个单元格都显示在屏幕上时,就会调用该方法,所以在不必要时,您可能会多次使用该方法。如果您的数据在创建的一个单元格和下一个单元格之间发生变化,则重新排序可能会打乱collectionView Indexath.row与数组索引之间的链接。我会在填充数组时对其进行排序,可能是在ViewWillDisplay或getWatchlistData方法中。如果数据在此之后发生更改,请使用其他一些collectionView委托/数据源方法来处理插入/删除/移动。但我不认为这是造成图像闪烁的原因 在发回主队列的代码中,调用cellForItemAtIndexPath方法,更新单元格映像并调用ReloadInputView,这可能会以某种方式重新配置单元格。但是,然后为所有可见的单元格调用ReloadItemSatinDexpath。这将导致collectionView为每个可见项重新调用cellForItemAtIndexPath数据源方法,从而从缓存中重新加载每个可见项的图像。我想这就是你闪烁的原因。我只需将下载的图像保存到缓存中,然后为受影响的indexPath调用reloadItemsAtIndexPaths。将调用cellForRowAtIndexPath数据源方法,并将从缓存中恢复图像并将其添加到新单元格中 同样,我认为cellForItemAtIndexPath末尾的重载ItemSatinDexpath是多余的,可能会导致闪烁 我认为您面临一些单元重用问题的风险-例如,您将微调器添加到每个单元。但是,出列的单元格可能以前已经显示过,因此已经有一个微调器,尽管它已停止,因此可能已隐藏。如果你经常来回滚动,你可能会得到一个有很多微调器的单元格,这会浪费内存。在将微调器添加为子视图之前,我会给它一个标记,然后使用viewWithTag确定是否已将微调器添加到已退出队列的单元格中。如果已添加,请将其删除。并且仅在必要时添加微调器,即在if…image==nil子句中 可能不太可能,但如果出列的单元格具有默认图像,则cell.imageView.image!=nil,并且正在为尚未缓存映像的单元格重新使用,因此cachedImage==nil,则不会执行任何分派方法,因此将永远不会下载映像
抱歉,如果这有点重,但我希望它有用。我也有同样的问题,任何图像下载后都会弹出视图。我将在前面重新加载该单元格,因此它将调用collectionview的一些委托方法。所以我删除了它,并为重新加载单元格创建了一个单独的方法。现在,当任何新映像重新加载时,我调用此方法,而不是重新加载CellForIndeXPath:。在自定义方法中,只需从cellForItemAtIndexPath复制粘贴代码:。在自定义方法中指定单元格。 CollectionPhotoItem单元格=CollectionPhotoItem[self.collection cellForItemAtIndexPath:indexPath]
就这样。它将显示您的手机,无需任何轻弹。谢谢。不用担心!我真的很感谢你的反馈。我刚刚开始学习Objective-C、iOS开发和编程,所以这些答案非常棒。我知道我做错了什么,但要让它正常工作还是要靠我自己。关于这个。。。我想它现在起作用了!我正在对数组进行排序,当它填充到getWatchListData方法中时,这似乎产生了很大的不同。基本上我做了你所有的建议。唯一的问题是,在第一次加载时,有时单元格中填充了错误的图像。你知道我该如何解决这个问题吗?只有几个要点:首先,检查你的缓存是否正确填充。在上一次运行中,它可能被错误地填充,即使您的代码现在可能没有问题。其次,要注意电池重复使用的问题,尤其是当你在列表中滚动时看到相同的图像时。我发现NSLog和断点非常有用 ul对追踪此类问题表示感谢。
[[DLImageLoader sharedInstance] displayImageFromUrl:@"image_url_here"
imageView:@"UIImageView here"];
[[DLImageLoader sharedInstance] loadImageFromUrl:@"image_url_here"
completed:^(NSError *error, UIImage *image) {
if (error == nil) {
// if we have no any errors
} else {
// if we got an error when load an image
}
}];