关于单元重用的自定义 UITableViewCell 约束问题

Posted

技术标签:

【中文标题】关于单元重用的自定义 UITableViewCell 约束问题【英文标题】:Custom UITableViewCell constraint issue on cell reuse 【发布时间】:2016-01-27 04:37:20 【问题描述】:

我有一个自定义的UITableViewCell,它具有动态图像高度。创建单元格时,所有调整大小的工作都按预期进行。问题是一旦单元格被UITableView 重用,图像高度的约束就会改变,并导致“无法同时满足约束”错误。

我尝试在重置之前停用高度限制,但它仍然会导致错误。

关于设置高度锚。这每次都会创建一个新实例,是否从内存中释放了停用的约束?有没有办法以这种格式更新当前约束?

我应该在 - (void)prepareForReuse 方法中做些什么吗?

感谢您的帮助

// Within Custom UITableViewCell
// The cell is a prototype cell in StoryBoard
// The width of the image is fixed and already set
// Observe when the image is set for imgView

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context 

if ([keyPath isEqualToString:@"image"]) 
    if(self.imgView.image) 

        CGFloat ratio = self.imgView.image.size.height / self.imgView.image.size.width;
        self.imageHeightConstraint.active = NO;
        self.imageHeightConstraint = [self.imgView.heightAnchor constraintEqualToAnchor:self.imgView.widthAnchor multiplier:ratio];
        self.imageHeightConstraint.identifier = @"imageHeightConstraint";
        self.imageHeightConstraint.active = YES;

    

UITableViewCell 自动调整大小,因为 UIImageViewUIStackView 中,其顶部和底部锚点固定在单元格 contentView 的顶部和底部。

- (void)buildUI 

    UIStackView *containerStackView = [UIStackView new];
    [self.contentView addSubview:containerStackView];
    containerStackView.translatesAutoresizingMaskIntoConstraints = NO;
    containerStackView.axis = UILayoutConstraintAxisHorizontal;
    containerStackView.distribution = UIStackViewDistributionFill;
    containerStackView.alignment = UIStackViewAlignmentCenter;
    containerStackView.spacing = 10;
    [containerStackView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:10.0].active = YES;
    [containerStackView.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor].active = YES;
    [containerStackView.widthAnchor constraintEqualToAnchor:self.contentView.widthAnchor multiplier:kImageWidthMultiplier].active = YES;
    [containerStackView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-30.0].active = YES;

    self.imgView = [UIImageView new];
    [containerStackView addArrangedSubview:self.imgView];
    self.imgView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.imgView.widthAnchor constraintEqualToAnchor:containerStackView.widthAnchor multiplier:0.492].active = YES;

【问题讨论】:

当你改变imageView的高度时,你是否也在增加UITableViewCell的高度? self.imageHeightConstraintweak 还是 strong 属性? 是的,UITableViewCell 自动调整大小以适合图像。 self.imageHeightConstraint 有一个 weak 引用。 尝试将其保留为strong,因为在停用约束后它可能是nil 我已经尝试过了,没有任何区别。 【参考方案1】:

计算动态表格视图单元格高度相当复杂。在您的情况下,单元格高度取决于图像高度。

重用表格视图单元格时,所有单元格的属性都将被重用,高度也不例外。进行更改的简单方法是使用heightForRowAtIndexPath,但使用自动布局计算高度时非常困难。

根据这篇文章 (http://www.raywenderlich.com/87975)。表格视图单元格中的子视图将被压缩,之后,我们可以轻松获取高度并返回heightForRowAtIndexPath。但是,需要一点时间来计算并使您的滚动不平滑,但我们可以使用estimatedRowHeight,您的表格视图将使用估计高度并申请特定行,然后我们才能准确计算该行的高度

以下是简短的演示代码:

//Estimate height (height could be 35, 42, 50, 29, etc)
//Just estimate a number
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath

    if (indexPath.row == 0) 
        return 40.0f;


//Your exactly height for row
- (CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell 
    [yourCustomCell setNeedsLayout];
    [yourCustomCell layoutIfNeeded];

    CGSize size = [yourCustomCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    return size.height;


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

    //only set once
    static YourCustomTableViewCell *yourCustomCell = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
        //load custom cell
        yourCustomCell = (YourCustomTableViewCell*)[Utils getCellNibFile:@"YourCustomTableViewCell" Owner:self];
);
    //get image from datasource
    UIImage* image = [self.dataSource objectAtIndex:indexPath];
    //set image for cell and begin calculate height after set image
    [yourCustomCell setImage:image];
    [self calculateHeightForConfiguredSizingCell:yourCustomCell];
    return height;

【讨论】:

以上是关于关于单元重用的自定义 UITableViewCell 约束问题的主要内容,如果未能解决你的问题,请参考以下文章

带有 UIProgressView 的自定义 UICollectionViewCell 在重用单元格上显示 progressView

UITableView 可重用的自定义单元格在子视图中显示错误的内容

来自笔尖的自定义 UiTableViewCell 没有重用?

用于重用的自定义 UIButton 类

从可重用单元中出列时,自定义 CollectionViewCell 上会触发啥方法?

表格视图中的自定义单元格未显示?