我有一个带有自定义UICollectionViewCell类的UICollectionView,我在其中绘制了必要的内容。然而,我发现当我向上和向下滚动集合视图时,它会重新绘制每个单元格,因为它会滚动并再次返回到屏幕上。这导致相当不稳定的滚动。我认为UICollectionViewCells是自动缓存和重用的,所以我不明白它为什么不断重绘它们。
我在自定义UICollectionViewCell的子视图的setNeedsDisplay中有一个NSLog语句,这就是我知道它重绘它们的原因。这是我用于绘制信息的UICollectionView代码。 (PFObject只是使用Parse从数据库中检索的对象)
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MiniCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MiniCell" forIndexPath:indexPath];
if (!cell.mini) {
PFObject *pfMini = [_searchResults objectAtIndex:indexPath.row];
Mini *mini = [Mini instanceWithPFObject:pfMini];
cell.mini = mini;
cell.backgroundColor = [UIColor grayColor];
}
return cell;
}
我的自定义单元格。这里的MiniView是我为显示图像而创建的自定义视图,我在其他各个地方使用它:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
MiniView *miniView = [[MiniView alloc] initWithFrame:rect];
miniView.mini = _mini;
[self addSubview:miniView];
UIImageView *backgroundImage = [[UIImageView alloc] initWithImage:[self randomBackground]];
self.backgroundView = backgroundImage;
}
- (UIImage *)randomBackground
{
int backgroundInt = arc4random()%26 + 8;
UIImage *background = [UIImage imageNamed:[NSString stringWithFormat:@"MainBackground%i", backgroundInt]];
return background;
}
答案 0 :(得分:4)
您应该将初始化语句放在initWithFrame:方法中。
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
MiniView *miniView = [[MiniView alloc] initWithFrame:rect];
miniView.mini = _mini;
[self addSubview:miniView];
UIImageView *backgroundImage = [[UIImageView alloc] initWithImage:[self randomBackground]];
self.backgroundView = backgroundImage;
}
return self;
}
我不记得在没有实际绘制内容的情况下初始化在drawRect:方法中完成。如果您想实际绘制单元格的内容,您应该使用图形上下文:
UIGraphicsBeginImageContext(self.bounds.size);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *imageOfContextSnapshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
这将获取当前上下文的“快照”。您可以将其视为将对象粘贴到画布上。在drawRect:方法中调用它应绘制您的内容。请注意,您应该只更新drawRect:方法中的上下文,否则您将收到并发生错误。此外,如果您实际上将调用绘图方法,则仅使用drawRect:方法。在创建新的UIView类时,drawRect:方法甚至声明只有在绘制内容时才应该使用该方法。
有关详细信息,请查看Apple的参考资料。他们对图形上下文以及如何使用它有非常详尽的解释。
编辑1:
根据单元格的数量,您可能需要考虑不绘制任何内容。 dequeueReusableCellWithIdentifier已经回收了单元格内容,并且做得非常好。你应该在必要的同时增加复杂性。虽然这对我来说很容易说,因为我不知道MiniView正在/正在做什么。
此外,如果您想要更好的性能,您可能需要考虑特定于对象的绘图方法,而不是使用renderInContext:。例如,NSSString具有:
-drawAtPoint:forWidth:withFont:
-drawAtPoint:forWidth:withFont:
对于绘制文本而言,这些表现更好,而不是渲染整个上下文。要绘制图像,您应该致电:
-drawInRect:
必须在图形上下文中调用它们,例如在drawRect:方法中。
编辑2:
在初始化init方法时不会绘制迷你,因为当你调用
时PFObject *pfMini = [_searchResults objectAtIndex:indexPath.row];
Mini *mini = [Mini instanceWithPFObject:pfMini];
cell.mini = mini;
cell.backgroundColor = [UIColor grayColor];
在视图控制器中,迷你视图已初始化并作为子视图添加到单元格中,但当分配MiniView的mini iVar时,单元格的mini iVar很可能是零。换句话说,当你在initWithFrame:(CGRect)框架方法中调用它时:
MiniView *miniView = [[MiniView alloc] initWithFrame:rect];
miniView.mini = _mini;
[self addSubview:miniView];
此时“_mini”为零。在你的cellForItemAtIndexPath:方法中,你正在分配单元格的mini,而不是MiniView的mini,因此MiniView的mini继续为零。您可以在cellForItemAtIndexPath中分配MiniView的mini:而不是单元格的mini,这应该可以解决它。
答案 1 :(得分:2)
您的单元格应代表模型中的一些数据。
现在我看到你为每个单元格创建了一个随机背景,但是可以根据需要创建和销毁单元格,所以你真的应该将这些信息存储在某个地方。
一旦您确定背景存储在视图控制器的@property NSArray *backgrounds
中,就可以使用标准模式:
@interface MyCell : UITableViewCell
@property NSString *backgroundName;
@property (weak) MiniView *miniView;
...
@implementation MyCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier] ) {
MiniView *miniView = [[MiniView alloc] initWithFrame:rect];
[self addSubview:miniView];
self.miniView = miniView;
// continue creating all necessary subviews ...
}
- (void)setBackgroundName:(NSString *)name {
// assign background
}
然后,当您将单元格出列时,可以使用cell.backgroundName = backgrounds[index]
。
答案 2 :(得分:0)
UICollectionView仅缓存并重用例如6中的可见单元格,即使你有100个。所以当你滚动它时,需要离屏的单元格然后作为新单元格去除。
如果要将所有单元格保存在内存中,可以创建单元格
MyCell *cell = [[MyCell alloc] initWithFrame:CGRectMake(...)];
并将它们存储在内部数组中(对于每一行),当委托请求已经创建的单元格时,你给了他一个来自array.This解决方案将消耗更多内存,因为所有单元格都将在内存中。