这是我在论坛问的一个问题:
之前写一个仿瀑布流demo的时候在tableView中添加子控件,由于tableview的复用机制,下拉出新的cell的时候子控件不会调用layoutSubview方法,于是上网学习发现需要在cell中强制让子控件刷新,即调用子控件item的layoutSubview方法。当时问题也确实解决了,于是借这次做电子书项目将其整理成了博客:
http://blog.youkuaiyun.com/u013604612/article/details/39578683。
但是这次结果下拉书架(tableview)的时候发现有重复数据,按照之前了解,是tableview的cell在复用时子控件没有调用layoutSubview方法。在子控件的layoutSubview方法中打断点,下拉的时候确实没有被中断。
在cell的layoutSubview方法中调用子控件item的setNeedsLayout方法或者是layoutIfNeeded方法都没有用。为什么?
//cell的layoutSubview方法
- (void)layoutSubviews
{
[super layoutSubviews];
for (int i = 0; i < self.booksGroup.count; i++) {
CYZBookItemView *item = (CYZBookItemView *)[self.contentView viewWithTag:100 + i];
item.frame = CGRectMake(kHorizontalEdge + (kHorizontalEdge + 80) * i, kVerticalEdge, 80, 150);
item.hidden = NO; //有数据的item不隐藏
item.bookModel = [self.booksGroup objectAtIndex:i];
[self addSubview:item];
//如果不添加以下方法,那么在cell复用时将不会调用子视图的layoutSubview方法,这样数据就无法更新了。
[item setNeedsLayout];
[item layoutIfNeeded];
}
}
//item的layoutSubview方法
- (void)layoutSubviews
{
[super layoutSubviews];
if (self.bookModel.isFromNative) {
UIImage *image = [UIImage imageNamed:[self.bookModel.images objectForKey:@"small"]];
if (image) {
[self.bookImage setBackgroundImage:image forState:UIControlStateNormal];
} else {
[self.bookImage setBackgroundImage:[UIImage imageNamed:@"default_book.png"] forState:UIControlStateNormal];
}
} else {
NSLog(@"%@", [NSURL URLWithString:[self.bookModel.images objectForKey:@"small"]]);
[self.bookImage setImageWithURL:[NSURL URLWithString:[self.bookModel.images objectForKey:@"small"]] placeholderImage:[UIImage imageNamed:@"default_book.png"]];
}
self.bookName.text = self.bookModel.title;
}
虽然说木人回复,但好歹也算解决了,在这里留下来供参考
一般来说cell的数据源协议中我们会这样写:
static NSString *cellId = @"CYZBookShelfViewCell";
CYZBookCell *cell = (CYZBookCell *)[tableView dequeueReusableCellWithIdentifier:cellId];
if (cell == nil) {
cell = [[CYZBookCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
cell.booksGroup = [self.bookGroup2D objectAtIndex:indexPath.row];
return cell;
在cell协议方法中,用deque方法取cell, 如果返回为nil则将调用initWithStyle:reuseIdentifier:方法初始化cell。而自定义的cell正是将初始化方法加在了这里面。我所谓的初始化,是指 将子视图item加到cell.contentView中并为之设tag值。而当deque方法不再返回nil的时候,此时便不再调用initWithStyle:reuseIdentifier:方法了,奇怪的是,这个时候对重用的cell, 用[cell.contentView viewWithTag:] 方法取不到item视图了(返回nil)。之前运行地挺好,ios8之后就不行了。不过 此时ios在取cell前会调用prepareForReuse方法。所以既然cell上有重复视图,并且cell没有初始化(添加子视图),那就在这个方法中处理即可。注意不要忘了super一下。
- (void)prepareForReuse
{
[super prepareForReuse];
[self removeAllSubviews];
[self p_initView];
}