在滚动期间重用UICollectionViewCells
我有一个问题,
我有一个简单的UICollectionView与静态200单元格,从Flickr加载图像。
我的CellForItemAtIndexPath看起来像这样:
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"FlickrCell" forIndexPath:indexPath]; cell.backgroundColor = [self generateRandomUIColor]; if(![[cell.subviews objectAtIndex:0] isKindOfClass:[PFImageView class]]) { NSURL *staticPhotoURL = [self.context photoSourceURLFromDictionary:[self.photos objectAtIndex:indexPath.row] size:OFFlickrSmallSize]; PFImageView *imageView = [[PFImageView alloc] initWithFrame:CGRectMake(0, 0, cell.frame.size.height, cell.frame.size.width) andImageURL:staticPhotoURL andOwningCell:cell]; [cell addSubview:imageView]; } return cell; }
PFImageView是UIImageView
一个子类,它在后台线程上加载一个Flickr照片URL,然后在主线程上更新它自己的图像 – 这工作正常。
逻辑非常简单 – 如果没有一个可出队的话,我创build一个单元格。
如果单元格(我期望被出队并且已经有一个PFImageView) 没有一个PFImageView,我分配并初始化一个imageView的单元格,并将其添加为单元格的子视图。
因此,我期望如果单元格已经出队,它应该已经有一个PFImageView作为子视图,因为我们不应该进入if语句来创build一个新的imageView,并启动一个新的照片下载请求
相反,我所看到的是,UICollectionView顶部和底部的单元“暂时离开屏幕” – 当它们回到屏幕上时,它们不会被重用,看起来新的单元格被创build并且图片刷新。
1)一旦单元格被创build,我怎样才能获得静态图像(即当单元格稍微离开屏幕时不刷新。
2)为什么细胞不被重复使用?
非常感谢您的时间。
约翰
我看到几个潜在的问题:
-
您正在专门查找您正在添加的子类的单元格的索引0。 UICollectionViewCell可能有其他的视图,所以你不能假设唯一的(或第一个)孩子是你添加的。
-
我没有看到你正在调用registerClass:forCellWithReuseIdentifier:或者registerNib:forCellWithReuseIdentifier :,其中一个是正确使用dequeue所必需的( https://developer.apple.com/library/ios/documentation/uikit/reference/ UICollectionViewCell_class / Reference / Reference.html )。
-
您只需设置PFImageView的URL就可以构buildPFImageView。 使可重用视图出列的想法是,您将只构造所需视图的一小部分,并且UITableView将在它们移出屏幕时回收它们。 即使不构build新内容,您也需要重置正在请求的indexPath的值。
如果您的情况如您所描述的那样简单,那么您可能会将您的PFImageView添加到已出队的UICollectionView的contentView属性中。
在你的控制器中:
// solve problem 2 [self.collectionView registerClass:[UICollectionViewCell class] forReuseIdentifer:@"FlickrCell"];
在collectionView:cellForItemAtIndexPath
UICollectionViewCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"FlickrCell" forIndexPath:indexPath]; cell.backgroundColor = [self generateRandomUIColor]; // solve problem 1 by looking in the contentView for your subview (and looping instead of assuming at 0) PFImageView *pfImageView = nil; for (UIView *subview in cell.contentView.subviews) { if ([subview isKindOfClass:[PFImageView class]]) { pfImageView = (PFImageView *)subview; break; } } NSURL *staticPhotoURL = [self.context photoSourceURLFromDictionary:[self.photos objectAtIndex:indexPath.row] size:OFFlickrSmallSize]; if (pfImageView == nil) { // No PFImageView, create one // note the use of contentView! pfImageView = [[PFImageView alloc] initWithFrame:CGRectMake(0, 0, cell.contentView.frame.size.height, cell.frame.size.width) andImageURL:staticPhotoURL andOwningCell:cell.contentView]; [cell.contentView addSubview:pfImageView]; } else { // Already have recycled view. // need to reset the url for the pfImageView. (Problem 3) // not sure what PFImageView looks like so this is an eg I'd probably remove the // URL loading from the ctr above and instead have a function that loads the // image. Then, you could do this outside of the if, regardless of whether you had // to alloc the child view or not. [pfImageView loadImageWithUrl:staticPhotoURL]; // if you really only have 200 static images, you might consider caching all of them } return cell;
对于不那么简单的情况(例如,我想在视觉上布局单元格,或者在内容中有多个孩子的地方),我通常使用Interface Builder自定义我的UICollectionViewCell。
- 在项目中创build一个UICollectionViewCell的子类(在你的情况下,称之为PFImageCell)。
- 添加一个IBOutlet属性到我想在初始化中改变的视图的子类(在你的情况下,一个UIImageView)。
@property (nonatomic, assign) IBOutlet UIImageView *image;
- 在Interface Builder中,为UITableView创build一个原型单元。
- 在该原型单元格的属性表中,将UICollectionViewCell子类标识为类。
- 为原型单元格提供属性表中的标识符(重用标识符)。
- 将界面生成器中的视图子添加到原型单元格(这里是一个UIImageView)。
- 使用IB将IBOutlet属性映射到添加的UIImageView
- 然后,在cellForRowAtIndexPath中出列,将出列结果强制转换为子类(PFImageCell)并设置IBOutlet属性实例的值。 在这里,你会为你的UIImageView加载适当的图像。
UICollectionView
将重用单元格以获得最大效率。 它不保证任何特定的重用或人口策略。 有趣的是,它似乎根据两个区域的整数幂来放置和移除单元格 – 例如,在非视网膜iPad上,它可能会将您的滚动区域分割成1024×1024的区域,然后在每个区域进入和退出时填充和减less这些区域的可见区域。 然而,你不应该对其确切的行为做任何预测。
另外,您使用集合视图单元格是不正确的。 请参阅文档 。 一个单元显式至less有两个子视图 – backgroundView
和contentView
。 所以,如果你添加一个子视图,它将在绝对最less的索引2,实际上,索引将是未定义的。 无论如何,你应该将子视图添加到contentView
,而不是单元格本身。
你正在做的最正常的方式是创build一个自定义的UICollectionView
子类,它内部有一个PFImageView
。
我不确定电池是否被重复使用。 它可能被重用,但子视图可能不在那里。 我的build议是创build一个PFImageViewCollectionViewCell类(UICollectionViewCell的子类),并将其注册为CollectionView单元格,并尝试。 这就是我如何做,如果我需要一个单元格内的子视图。
尝试在这个特定的UIImageView
上添加一个标签
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath { static int photoViewTag = 54353532; UICollectionViewCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"FlickrCell" forIndexPath:indexPath]; cell.backgroundColor = [self generateRandomUIColor]; PFImageView *photoView = [cell.contentView viewWithTag:photoViewTag]; // Create a view // if (!photoView) { photoView = [[PFImageView alloc] initWithFrame:CGRectMake(0, 0, cell.frame.size.height, cell.frame.size.width) andImageURL:staticPhotoURL andOwningCell:cell]; imageView.tag = photoViewTag; [cell.contentView addSubview:imageView]; } // Update the current view // else { NSURL *staticPhotoURL = [self.context photoSourceURLFromDictionary:[self.photos objectAtIndex:indexPath.row] size:OFFlickrSmallSize]; photoView.imageURL = staticPhotoURL; } return cell; }
我真的build议创build自己的UICollectionViewCell
子类。
编辑:另外,请注意,我使用contentView
属性,而不是直接将其添加到单元格。
- iOS 11中拖放功能的简单示例
- 在iOS中,什么是types的buf返回'sysctlbyname(“net.inet.tcp.pcblist”,buf,&len,0,0)'?
- 添加Swift文件来testing目标没有修复unit testing
- SQLite3错误 – iOS
- IOS,ARC,属性:(readwrite,nonatomic)vs(radwrite,retain,nonatomic)
- iOS 8 PhotoKit。 从iCloud照片共享相册中获取最大尺寸的图像
- 如何有效地设置HTTP身体请求?
- 检测是否使用colorWithPatternImage创build了UIColor
- 当我重新使用它时,如何完全清除单元格?