Auto layout of custom programmatic UITableViewCell

2019-05-12 05:54发布

I'm trying to use the new auto layout capability of iOS 6 on a custom UITableViewCell which has been implemented programmatically. I added the addConstraint calls, and it works properly at first-- until I scroll. When I come back to the cell after scrolling the layout is trashed. By trashed I mean the margins between fields are all wrong (too large, well beyond the size of the cell). I'm speculating this has something to do with the dequeueReusableCellWithIdentifier method leaving me with a "dirty" cell, the same way you find yourself needing to reinitialize fields within cells, but I can't seem to do anything to coax it to render properly again. I've tried calling [self.contentView updateConstraints] before returning the cell. I've tried destroying the constraints and recreating them. Not only does it not work, but if it's attempted in layoutSubviews it freezes in an endless loop of some kind. Any ideas?

Here's the code to establish the constraints. It's located in initWithStyle:reuseIdentifier:

[self.completedLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.nextSetHeaderLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.nextSetDetailLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.youWillLearnHeaderLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.youWillLearnDetailLabel setTranslatesAutoresizingMaskIntoConstraints:NO];

[self.contentView removeConstraints:[self.contentView constraints]];

NSDictionary *views = NSDictionaryOfVariableBindings(_completedLabel, _nextSetHeaderLabel, _nextSetDetailLabel, _youWillLearnHeaderLabel, _youWillLearnDetailLabel);

[self.contentView addConstraints:
 [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-5-[_completedLabel]-5-|"
                                         options:0
                                         metrics:nil
                                           views:views]];
[self.contentView addConstraints:
 [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-5-[_nextSetHeaderLabel]-5-|"
                                         options:0
                                         metrics:nil
                                           views:views]];

[self.contentView addConstraints:
 [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-5-[_nextSetDetailLabel]-5-|"
                                         options:0
                                         metrics:nil
                                           views:views]];

[self.contentView addConstraints:
 [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-5-[_youWillLearnHeaderLabel]-5-|"
                                         options:0
                                         metrics:nil
                                           views:views]];

[self.contentView addConstraints:
 [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-5-[_youWillLearnDetailLabel]-4-|"
                                         options:0
                                         metrics:nil
                                           views:views]];

[self.contentView addConstraints:
 [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-5-[_completedLabel]-12-[_nextSetHeaderLabel]-0-[_nextSetDetailLabel]-12-[_youWillLearnHeaderLabel]-0-[_youWillLearnDetailLabel(>=20)]-1-|"
                                         options:0
                                         metrics:nil
                                           views:views]];

2条回答
▲ chillily
2楼-- · 2019-05-12 06:17

I ran into this issue as well. If I wasn't dequeuing cells, everything seemed to work - scrolling, rotation etc. However, if I dequeued cells, then the layout started getting messed up. The only way I could get it to work was by overriding the cell's prepareForReuse method. In this method,

    1. remove all the custom subviews
    2. remove all constraints associated with those subviews from contentView
    3. add subviews and constraints again
-(void) prepareForReuse
{
    [self removeCustomSubviewsFromContentView];
    [self.contentView removeConstraints:self.constraints] //self.constraits holds all the added constraints
    [self setupSubviewsInContentView];
    [self addConstraintsToContentView];
}

If there is a better way to do this, I would love to learn as well :) I believe the advantage of dequeing is that the tableView does not have to hold a large number of cells in memory - but, with this method, one has to go through the cost of essentially setting up the cell everytime you dequeue.

查看更多
Juvenile、少年°
3楼-- · 2019-05-12 06:28

I had a similar problem, in case anyone is interested I've found a solution, see this question

What I've done:

- (void)awakeFromNib
{
    [super awakeFromNib];

    for (NSLayoutConstraint *cellConstraint in self.constraints)
    {
        [self removeConstraint:cellConstraint];

        id firstItem = cellConstraint.firstItem == self ? self.contentView : cellConstraint.firstItem;
        id seccondItem = cellConstraint.secondItem == self ? self.contentView : cellConstraint.secondItem;

        NSLayoutConstraint* contentViewConstraint = [NSLayoutConstraint constraintWithItem:firstItem
                                                                                 attribute:cellConstraint.firstAttribute
                                                                                 relatedBy:cellConstraint.relation
                                                                                    toItem:seccondItem
                                                                                 attribute:cellConstraint.secondAttribute
                                                                                multiplier:cellConstraint.multiplier
                                                                                  constant:cellConstraint.constant];

        [self.contentView addConstraint:contentViewConstraint];
    }
}
查看更多
登录 后发表回答