ios8 UITableViewCell重用时自定义子视图不更新问题

在实现瀑布流效果的UITableView中遇到子控件在cell重用时不更新的问题。通过强制调用子控件的layoutSubview方法来解决,但在实际项目中,使用setNeedsLayout或layoutIfNeeded无效。通过研究和实践,找到了解决方案,并在博客中分享了详细过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是我在论坛问的一个问题:

之前写一个仿瀑布流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];
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值