iosuitableviewautolayout

UITableViewCell 's content height constraint can not refresh in reloadData?


I have a simple demo AutoSizing UITableView project like this : when you tap the tableview cells will make cell's red subview ‘s height constraint to bigger value(from original 60 to 100) and calling reloadData.

#import "ViewController.h"
#import "TestCell.h"

@interface ViewController ()<UITableViewDelegate,UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic,assign) NSInteger value;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.tableView.dataSource = self;
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    self.tableView.delegate = self;
    [self.tableView registerNib:[UINib nibWithNibName:@"TestCell" bundle:nil] forCellReuseIdentifier:@"TestCell"];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 3;
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TestCell* cell = (TestCell*)[tableView dequeueReusableCellWithIdentifier:@"TestCell" forIndexPath:indexPath];
    cell.value  = self.value;
    return cell;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 1;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    self.value += 1;
    [self.tableView reloadData];
}

and the cell:

#import "TestCell.h"
@interface TestCell()
@property (weak, nonatomic) IBOutlet UIView *redView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightConstraint;//red view's height constraint
@end

@implementation TestCell

- (void)awakeFromNib {
    [super awakeFromNib];
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

- (void)setValue:(NSInteger)value
{
    if (value > 1)
    {
        self.heightConstraint.constant = 100;
    }
    [self setNeedsLayout];
    [self setNeedsUpdateConstraints];
}

@end

And the cell's xib is containing just one subview in it: enter image description here

But when I invoke the reloadData, there will be a constraints break warning like this

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. 
(
    "<NSLayoutConstraint:0x6000021279d0 UIView:0x10d615680.height == 100   (active)>",
    "<NSLayoutConstraint:0x600002126f80 V:[UIView:0x10d615680]-(10)-|   (active, names: '|':UITableViewCellContentView:0x10d6154c0 )>",
    "<NSLayoutConstraint:0x600002127070 V:|-(0)-[UIView:0x10d615680]   (active, names: '|':UITableViewCellContentView:0x10d6154c0 )>",
    "<NSLayoutConstraint:0x6000021277a0 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x10d6154c0.height == 70   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x6000021279d0 UIView:0x10d615680.height == 100   (active)>

There is a UIView-Encapsulated-Layout-Height constraint here , I think this constraint is generated by the layout system at the first layout .

If I call the reloadData afterwise, The layout will still use that cell height constraint genereated before (height:70), so If I change the subview's height to 100 , This will make a conflict .

I think the height constraint generated by system should be invalid at sometime . Is there anyway to do this?


Solution

  • When a table view lays out its cells, the cells inherit a height constraint. If you do something to change the cell's views constraints (such as changing the red view's height constant), there will be an auto-layout conflict until the next layout pass.

    Assuming your redView has a bottom constraint to the bottom of the cell's contentView...

    Change the Priority of that bottom constraint to 999. That will get rid of the auto-layout complaints.

    Side note -- these lines are not needed:

    [self setNeedsLayout];
    [self setNeedsUpdateConstraints];