Ios 滚动期间重复使用UICollectionViewCells

Ios 滚动期间重复使用UICollectionViewCells,ios,iphone,uikit,uicollectionview,uicollectionviewcell,Ios,Iphone,Uikit,Uicollectionview,Uicollectionviewcell,我有个问题 我有一个简单的UICollectionView,有一个静态的200个单元格,可以从Flickr加载图像 我的CellForItemAtIndexPath如下所示: - (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewCell *cell = [cv dequeueReus

我有个问题

我有一个简单的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,然后在主线程上更新它自己的图像-这很好

逻辑非常简单——如果没有一个可排队的单元,我就创建一个单元

如果单元格(我希望它已退出队列,并且已经有一个PFImageView)没有PFImageView,我为该单元格分配并初始化一个imageView,并将其添加为单元格的子视图

因此,我希望如果单元格已出列,它应该已经有一个PFImageView作为子视图,并且我们不应该进入if语句来创建一个新的imageView并启动一个新的照片下载请求

相反,我看到的是,UICollectionView顶部和底部的单元格瞬间“离开屏幕”——当它们回到屏幕上时,它们没有被重用,似乎创建了一个新的单元格并刷新了图片

1) 创建单元格后如何获得静态图像(即当单元格稍微离开屏幕时不刷新)

2) 为什么电池没有被重复使用

非常感谢你的时间


约翰

我不确定这个电池是否被重复使用。它可能被重用,但子视图可能不存在。我的建议是创建一个PFImageViewCollectionViewCell类(UICollectionViewCell的子类),并将其注册为CollectionView单元格,然后重试。如果我需要单元格内的子视图,我会这样做。

我不确定单元格是否被重复使用。它可能被重用,但子视图可能不存在。我的建议是创建一个PFImageViewCollectionViewCell类(UICollectionViewCell的子类),并将其注册为CollectionView单元格,然后重试。如果我需要单元格内的子视图,我会这样做。

我发现了几个潜在问题:

  • 您正在为要添加的子类查看单元格的索引0。UICollectionViewCell可能有其他视图作为子视图,因此不能假定唯一(或第一个)子视图就是您添加的子视图

  • 我看不到您正在调用registerClass:forCellWithReuseIdentifier:或registerInB:forCellWithReuseIdentifier:,其中一个是正确使用出列()所必需的

  • 您仅在必须构造PFImageView的情况下设置PFImageView的URL。取消可重用视图队列的想法是,您将只构建所需视图的一小部分,而UITableView将在视图移出屏幕时回收它们。您需要重置所请求的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 e.g. 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

  • 在项目中创建UICollectionViewCell的子类(在您的情况下,将其称为PFImageCell)
  • 为我想在初始化中更改的视图(在您的例子中是UIImageView)的子类添加一个IBOutlet属性。
    @property(非原子,赋值)ibuiimageview*image
  • 在Interface Builder中,为UITableView创建原型单元
  • 在该原型单元的属性表中,将UICollectionViewCell子类标识为类
  • 在属性表中为原型单元指定一个标识符(重用标识符)
  • 将interface builder中的视图子级添加到prototype单元(此处为UIImageView)
  • 使用IB将IBOutlet属性映射到添加的UIImageView
  • 然后,在CellForRowatineXpath中出列时,将出列结果强制转换为子类(PFImageCell),并设置IBOutlet属性实例的值。在这里,您将为UIImageView加载适当的图像

  • 我看到了几个潜在的问题:

  • 您正在为要添加的子类查看单元格的索引0。UICollectionViewCell可能有其他视图作为子视图,因此不能假定唯一(或第一个)子视图就是您添加的子视图

  • 我看不到您正在调用registerClass:forCellWithReuseIdentifier:或registerInB:forCellWithReuseIdentifier:,其中一个是正确使用出列()所必需的

  • 您只在必须构造PFImageView的情况下设置PFImageView的URL。取消可重用视图队列的想法是,您将只构建所需视图的一小部分,而UITableView将在视图移出屏幕时回收它们。您需要重置所请求的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 e.g. 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

  • 在项目中创建UICollectionViewCell的子类(在您的情况下,将其称为PFImageCell)
  • 为我想在初始化中更改的视图(在您的例子中是UIImageView)的子类添加一个IBOutlet属性。
    @属性(非原子,赋值)IBOUTLE UIImageView*imag