表视图可重复使用的自上浆细胞与改变子视图

问题描述:

我有一个UITableView表视图可重复使用的自上浆细胞与改变子视图

self.tableView = [[UITableView alloc] init]; 
self.tableView.rowHeight = UITableViewAutomaticDimension; 
self.tableView.estimatedRowHeight = 60.0f; 
self.tableView.delegate = self; 
self.tableView.dataSource = self; 
[self.tableView registerClass:[MyTableViewCell class] forCellReuseIdentifier:NSStringFromClass([MyTableViewCell class])]; 

和一个自定义UITableViewCell与自定义视图:

@implementation MyTableViewCell { 

} 

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 
    if (self) { 
     [self setupView]; 
    } 

    return self; 
} 

- (void)setupView { 
    self.wrapperView = [UIView new]; 
    [self.contentView addSubview:self.wrapperView]; 

    self.firstView = [UIView new]; 
    self.secondView = [UIView new]; 
} 

- (void)prepareForReuse { 
    [super prepareForReuse]; 

    [self.wrapperView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 
} 

- (void)updateConstraints { 
    [self.wrapperView mas_updateConstraints:^(MASConstraintMaker *make) { 
     make.edges.equalTo(self.contentView); 
    }]; 

    UIView *previous; 
    for (NSUInteger index = 0; index < self.wrapperView.subviews.count; index++) { 
     UIView *subview = self.wrapperView.subviews[index]; 
     [subview mas_makeConstraints:^(MASConstraintMaker *make) { 
      if (!previous) { 
       make.top.equalTo(self.wrapperView); 
      } 
      else { 
       make.top.equalTo(previous.mas_bottom); 
      } 

      make.left.equalTo(self.wrapperView); 
      make.right.equalTo(self.wrapperView); 
      make.height.equalTo(@50.0f); 

      if (index == self.wrapperView.subviews.count - 1) { 
       make.bottom.equalTo(self.wrapperView); 
      } 
     }]; 

     previous = subview; 
    } 

    [super updateConstraints]; 
} 

- (void)populate:(NSInteger)index { 
    [self.wrapperView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 

    [self.wrapperView addSubview:self.firstView]; 
    if (index % 2 == 0) { 
     [self.wrapperView addSubview:self.secondView]; 
    } 

    [self updateConstraints]; 
} 

@end 

UITableViewDelegate被实现为这样:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    MyTableViewCell *cell = (MyTableViewCell *) [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MyTableViewCell class])]; 
    [cell populate:indexPath.row]; 

    return cell; 
} 

正如你所看到的,我交替显示secondView和交替即时改变约束(使用砖石)到wrapperView边缘结合到它的子视图时(以允许自调整大小)

的问题是它似乎重用细胞时UITableView无法弄清楚的高度。这将导致以下两个错误发生向下滚动单元时:

错误1:(这里其抱怨那里有太多“高度”(50像素),因为我们正在重用,其用于显示secondView小区)

2015-10-19 09:52:54.075 SelfsizingTest[32296:1615907] Unable to simultaneously satisfy constraints. 
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<MASLayoutConstraint:0x7fc5c3adaf40 UIView:0x7fc5c3ad9750.top == UITableViewCellContentView:0x7fc5c3ad8f30.top>", 
    "<MASLayoutConstraint:0x7fc5c3adb1c0 UIView:0x7fc5c3ad9750.bottom == UITableViewCellContentView:0x7fc5c3ad8f30.bottom>", 
    "<MASLayoutConstraint:0x7fc5c1543da0 UIView:0x7fc5c3ad9980.top == UIView:0x7fc5c3ad9750.top>", 
    "<MASLayoutConstraint:0x7fc5c15453c0 UIView:0x7fc5c3ad9980.bottom == UIView:0x7fc5c3ad9750.bottom>", 
    "<MASLayoutConstraint:0x7fc5c3c0d5d0 UIView:0x7fc5c3ad9980.height == 50>", 
    "<NSLayoutConstraint:0x7fc5c3ae2440 UITableViewCellContentView:0x7fc5c3ad8f30.height == 100>" 
) 

Will attempt to recover by breaking constraint 
<MASLayoutConstraint:0x7fc5c3c0d5d0 UIView:0x7fc5c3ad9980.height == 50> 

错误2:(这里其抱怨说那里有没有足够的“高度”,以允许要被显示secondView(缺少50pixels))再利用以前不显示secondView

一个小区时偏偏
2015-10-19 10:02:49.667 SelfsizingTest[32565:1625337] Unable to simultaneously satisfy constraints. 
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<MASLayoutConstraint:0x7f9628420250 UIView:0x7f962841eb40.top == UITableViewCellContentView:0x7f962841b1e0.top>", 
    "<MASLayoutConstraint:0x7f96284204d0 UIView:0x7f962841eb40.bottom == UITableViewCellContentView:0x7f962841b1e0.bottom>", 
    "<MASLayoutConstraint:0x7f9628421560 UIView:0x7f962841ed70.height == 50>", 
    "<MASLayoutConstraint:0x7f9628628a70 UIView:0x7f962841ed70.top == UIView:0x7f962841eb40.top>", 
    "<MASLayoutConstraint:0x7f96286293e0 UIView:0x7f962841eef0.top == UIView:0x7f962841ed70.bottom>", 
    "<MASLayoutConstraint:0x7f9628629d80 UIView:0x7f962841eef0.height == 50>", 
    "<MASLayoutConstraint:0x7f9628629f00 UIView:0x7f962841eef0.bottom == UIView:0x7f962841eb40.bottom>", 
    "<NSLayoutConstraint:0x7f9628422490 UITableViewCellContentView:0x7f962841b1e0.height == 50>" 
) 

Will attempt to recover by breaking constraint 
<MASLayoutConstraint:0x7f9628629d80 UIView:0x7f962841eef0.height == 50> 

所以我的问题是,如何在细胞“群体”期间改变其子视图结构的细胞时,如何使用自我大小细胞。

我想解决这个问题的一种方法是为每个组合提供一个单独的单元格,但在我的“真实”情况下,这会导致很多单元格。

伊夫上传的例子项目中,我重现该问题: https://www.dropbox.com/s/uyyzvxpkud7bcta/SelfsizingTest.zip?dl=0

计算你的身高在布局子视图,并在实例变量进行分配。计算将基于所需的数据和涉及的子视图。

- (void)layoutSubviews { 

    [super layoutSubviews]; 
    ..... 
    self.heightEstimated = <some_variable_you_calulate_required_height_based_onSubview>; 
} 

然后创建它仅用于计算高度

虚设单元可变

static MyCell *_mannequinCell;

现在创建一个虚拟池只有一次

+ (MyCell *)mannequinCell { 
    if (!_mannequinCell) { 
     _mannequinCell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MyCellIdentifier"]; 
    } 
    return _mannequinCell; 
} 

现在,只要你需要找规模基于这些数据,这些数据可能因数据/子视图而有所不同。只需创建一个如下所示的方法。

+ (CGFloat)heightRequiredWithData:(Model *)data { 
    [[MyCell mannequinCell] populateCellWithData:data]; 
    [[MyCell mannequinCell] layoutSubviews]; 
    return [MyCell mannequinCell].heightEstimated; 
} 
+0

这种做法更象是在使用前UITableView的自调整大小做支撑,这将是巨大的,如果我能继续使用自调整大小的细胞,而不是手动计算单元格的高度。 –