滚动期间重复使用UICollectionViewCells [英] Reuse of UICollectionViewCells during scrolling

查看:70
本文介绍了滚动期间重复使用UICollectionViewCells的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到问题

我有一个简单的UICollectionView,其中包含200个静态单元格,可从Flickr加载图像.

I have a simple UICollectionView with a static 200 cells that load images from Flickr.

我的CellForItemAtIndexPath看起来像这样:

my CellForItemAtIndexPath looks like this:

- (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 is a subclass of UIImageView that loads a Flickr photo URL on a background thread and then updates it's own image on the main thread - this works fine.

逻辑非常简单-如果没有一个可出队,我将创建一个单元.

The logic is really simple - I create a cell if there isn't one dequeueable.

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

If the cell (which I'm expecting to be dequeued and already have a PFImageView) doesn't have a PFImageView, I alloc and init an imageView for the cell and add it as a subview of the cell.

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

相反,我看到的是UICollectionView顶部和底部的单元格暂时不在屏幕上"-当它们回到屏幕上时,它们不再被重用,并且似乎创建了一个新的单元格并刷新了图片.

Instead what I see is that the cells at the top and bottom of the UICollectionView that 'go off screen' momentarily - when they come back on screen they are not being reused and seemingly a new cell is created and the picture refreshed.

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

1) How can I achieve a static image once the cell has been created (i.e. not refreshing when the cell goes slightly off screen.

2)为什么不重复使用这些电池?

2) Why are the cells not being reused?

非常感谢您的宝贵时间.

Many thanks for your time.

约翰

推荐答案

我看到了一些潜在的问题:

I see several potential issues:

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

  1. You are looking specifically at index 0 of the cell for the child class that you are adding. The UICollectionViewCell may have other views as children, so you can't just assume that the only (or first) child is the one you added.

我看不到您在调用registerClass:forCellWithReuseIdentifier:或registerNib:forCellWithReuseIdentifier :,正确使用出队是其中之一(

I don't see that you are calling registerClass:forCellWithReuseIdentifier: or registerNib:forCellWithReuseIdentifier:, one of which is required for proper use of dequeue (https://developer.apple.com/library/ios/documentation/uikit/reference/UICollectionViewCell_class/Reference/Reference.html).

仅在必须构造PFImageView的情况下设置PFImageView的URL.使可重用视图出队的想法是,您将仅构造所需视图的一小部分,并且UITableView将在它们移出屏幕时对其进行回收.即使您不构造新内容,也需要重置请求的indexPath的值.

You are only setting the URL of the PFImageView in the case that you have to construct the PFImageView. The idea with dequeuing reusable views is that you will only construct a small subset of the views needed, and the UITableView will recycle them as they move offscreen. You need to reset the value for the indexPath that is being requested, even when you don't construct the new content.

如果您的情况很简单,那么您可以将PFImageView添加到出列的UICollectionView的contentView属性中.

If your case is as simple as you describe, you can probably get away with adding your PFImageView to the contentView property of your dequeued UICollectionView.

在您的控制器中:

// solve problem 2
[self.collectionView registerClass:[UICollectionViewCell class] forReuseIdentifer:@"FlickrCell"];

在collectionView:cellForItemAtIndexPath

In 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.

For less simple cases (e.g. where I want to visually lay out the cell, or where I have multiple children in the content), I typically customize my UICollectionViewCell's using Interface Builder.

  1. 在项目中创建UICollectionViewCell的子类(在您的情况下,将其称为PFImageCell).
  2. 为要在初始化中更改的视图(在您的情况下为UIImageView)向该子类添加IBOutlet属性. @property (nonatomic, assign) IBOutlet UIImageView *image;
  3. 在Interface Builder中,为UITableView创建一个原型单元.
  4. 在该原型单元的属性表中,将UICollectionViewCell子类标识为该类.
  5. 在属性表中给原型单元一个标识符(重用标识符).
  6. 在界面生成器中将视图子项添加到原型单元(此处为UIImageView).
  7. 使用IB将IBOutlet属性映射到添加的UIImageView
  8. 然后,在cellForRowAtIndexPath中出队时,将出队结果转换为子类(PFImageCell),并设置IBOutlet属性实例的值.在这里,您将为UIImageView加载正确的图像.
  1. Create a subclass of UICollectionViewCell in the project (In your case, call it PFImageCell).
  2. Add an IBOutlet property to that subclass for the view I want to change in initialization (In your case, a UIImageView). @property (nonatomic, assign) IBOutlet UIImageView *image;
  3. In Interface Builder, create a prototype cell for the UITableView.
  4. In the properties sheet for that prototype cell, identify the UICollectionViewCell subclass as the class.
  5. Give the prototype cell an identifier (the reuse identifier) in the property sheet.
  6. Add the view child in interface builder to the prototype cell (here, a UIImageView).
  7. Use IB to map the IBOutlet property to the added UIImageView
  8. Then, on dequeue in cellForRowAtIndexPath, cast the dequeued result to the subclass (PFImageCell) and set the value of the IBOutlet property instance. Here, you'd load the proper image for your UIImageView.

这篇关于滚动期间重复使用UICollectionViewCells的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆