IOS 8 self-adjusting cells with variable height

I have created a table view with self-configuring UITableViewCells using

tableview.rowHeight = UITableViewAutomaticDimension;

To test the created single UIView

and add it to cell.contentView

with the following restrictions. (using masonry)

- (void)updateConstraints {
    UIView *superview = self.contentView;

    if (!_didSetupConstraints) {
        [self.testView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(superview);
            make.height.equalTo(@10.0f);
            make.left.equalTo(superview);
            make.right.equalTo(superview);
            make.bottom.equalTo(superview);
        }];

        _didSetupConstraints = YES;
    }

    [super updateConstraints];
}

      

When I select a row, I like to change the height of the selected cell. I'm doing it:

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

    [self.testView mas_updateConstraints:^(MASConstraintMaker *make) {
        if (selected) {
            make.height.equalTo(@100);
        }
        else {
            make.height.equalTo(@10);
        }
    }];

    [UIView animateWithDuration:0.3f animations:^{
        [super layoutIfNeeded];
    }];
}

      

Seems to work, but xcode complaints with the following error:

Unable to simultaneously satisfy constraints.

The problem then is that it contentView

creates its own height constant (because contentView.translatesAutoresizingMaskIntoConstraints = YES;

by default).

So when updateConstraints is run first, the system will create a height constraint contentView

equal to10.0f

then when setSelected...

i is called, changes the height of mine testView

, so a conflict between testView.height

(100.0f) and contentView.height

(10.0f) and since it is testView

attached to the bottom contentView

(in order to work with cells for self-sizing) it gives errors too.

I tried to set contentView.translatesAutoresizingMaskIntoConstraints = NO;

, but then it seems that the UITableViewCell cant really figure out the correct cell size. (sometimes too wide / too small), etc.

What is the proper way to implement self-aligning cells that can dynamically change their height?

+3


source to share


1 answer


There are two problems here:

1. AutoLayout message: Unable to simultaneously satisfy constraints.

This is because you updated the custom view constraint height

, but you are not updating the constraint contentView

height

. Since you are also setting the custom view constraint bottom

on the contentView bottom

, the system cannot satisfy both constraints: a custom view cannot have a height of 100 and at the same time connect to the bottom of the contentView while the ContentView is still 10.

The fix is ​​pretty simple. You define a height constraint for the contentView and set it to the height of your custom view:

[self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.height.equalTo(self.testView);
}];

      

This fixes the problem.

2. Updating cell height

Updating the cell height is not easy because the cell heights are processed UITableViewController

and not the cells themselves. You can of course change the height of your cell, but until UITableViewController

you give the cell enough space, you won't see the new cell height. You will see that your top cell will overlap the next cell.



So, you need to specify UITableViewController

that it should update the height of your cell. You can do this by calling reloadRowsAtIndexPaths:withRowAnimation:

. This reloads the cell and also revives it. Thus, the cell must somehow call this method on UITableViewController

. The challenge is there: A UITableViewCell

has no reference to it UITableViewController

(and it shouldn't).

What you can do is subclass UITableViewCell

and give it a closure property that it can execute when its height changes:

class DynamicHeightTableViewCell: UITableViewCell {
    var heightDidChange: (() -> Void)?
    ...

      

Now, when you deactivate a cell in yours UITableViewControllerDataSource

, you set its closure:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("DynamicHeightTableViewCell", forIndexPath: indexPath)
    if let customCell = cell as? DynamicHeightTableViewCell {
        customCell.heightDidChange = { [weak cell, weak tableView] in
            if let currentIndexPath = tableView?.indexPathForCell(cell!) {
                tableView?.reloadRowsAtIndexPaths([currentIndexPath], withRowAnimation: .Automatic)
            }
        }
    }

    return cell
}

      

And then when the cell changes its height, you just do a close and the cell will be reloaded:

func theFunctionWhereTheHeightChanges() {

   // change the height

   heightDidChange?()
}

      

0


source







All Articles