Home > Net >  Adaptive height for UITableViewCell containing an UITableView
Adaptive height for UITableViewCell containing an UITableView

Time:10-01

I have an UITableView (let's call it table1) which contains static rows. The first row contains another UITableView (table2), populated dynamically from an XML file on the internet, which is completed after the cell is being created, because asynchronous. table2 is created and added to cell's contentView only once the request is done (else an error text is prompted as cell's label).

table2 is made of collapsed sections that are expanded when interacted, which thus do change the contentSize/height of the table2.

What I want to achieve is to make the cell of table1 resize dynamically at 2 key points: 1 when the web request is done, which means when the table is created and added as subview, and 2 when a section of table2 is interacted, which makes the height of table1 change; table1 cell should follow and do exactly the same height variation.

I've searched everywhere and tried tons of things, but nothing ever worked, and I've been stuck for days.

Here's what I've tried:

  • Overriding (estimated)heightForRowAtIndexPath:: useless as it's only called once and before table2 is added
  • Changing UITableViewAutomaticDimension and estimatedRowHeight: done by default
  • Using NSLayoutConstraints, within updateConstraints or after table2 creation
  • Playing with intrinsicContentSize and invalidateIntrinsicContentSize:
  • Using reloadRowsAtIndexPaths:withRowAnimation:

...but nothing worked, and I feel I've tried everything

About the constraints, I tried something like: table2.top = contentView.top = cell.top (same for leading & trailing) cell.bottom = contentView.bottom = table2.bottom (also with height)


EDIT 1:
My code:


// Cell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        self.openSection = -1; // reports which section of table2 is open
        SPDSpinnerView *spinner = [[SPDSpinnerView alloc] initWithFrame:self.frame]; // view with UIActivityIndicator & text
        spinner.label.text = @"Loading...";
        [self addSubview:spinner];
        self.contentView.translatesAutoresizingMaskIntoConstraints = NO;

        [self loadDataWithCompletion:^(BOOL success) {
            // Remove spinner
            for (UIView *view in [self subviews]) {
                if ([view isKindOfClass:[SPDSpinnerView class]]) [view removeFromSuperview];
            }
            // Handle result
            if (success) {
                // Add table view when done
                self.table2 = [[UITableView alloc] initWithFrame:self.frame style:UITableViewStylePlain];
                self.table2.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
                [self.table2 registerClass:[SPDChangelogHeaderView class] forHeaderFooterViewReuseIdentifier:@"headerView"]; // custom tappable header for collapsible sections
                self.table2.scrollEnabled = NO;
                self.table2.delegate = self;
                self.table2.dataSource = self;
                self.table2.translatesAutoresizingMaskIntoConstraints = NO;
                [UIView transitionWithView:self.contentView duration:.25 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
                    [self.contentView addSubview:self.table2];
                    // FIXME: fit table2 in cell
                } completion:nil];
            } else {
                self.textLabel.text = @"Error loading data";
            }
        }];
    }
    return self;
}

// delegates, touch handler for table2, and data loader

(nothing else related to my problem aside from usual code)


EDIT 2:
"Mockups:"
What it looks like currently

What I want it to be at step 1 (after data loading)

What I want it to be when inner sections are collapsed or expanded

For (2) and (3), red lines are the height I want for both table2 and the cell. In this MRE, table2 overlaps the rest of table1 but I want of course to keep the same spacing between cells of table1, table1 must grow as the cell does.


Thank you!

CodePudding user response:

So, with the kind help of DonMag, I've reconsidered my issue. My idea was to embed a whole table in my cell: instead, they proposed to use subsections. A link is worth thousand words:

github.com/DonMag/SubSectionsDemo

If you want further explanation on how it works, let me explain. Basically, the idea is to create 2 kinds of cells you want to "simulate" your embedded table with: (sub)headers & (sub)cells. They will both be cells belonging to the section of your table1, with 2 different looks.
Then, to recreate the collapsing effect, you have to handle cells selection but only for subheader cells in tableView:didSelectRowAtIndexPath:.
Cell collapsing is done by reloading data and then adding to table1 section, during the reloading, only subcells that are not virtually collapsed, and all the subheaders.
Hope it was clear enough to help you understand the code above on GitHub.

Unfortunately I won't be using this as-is because I do use a special subclass of UITableViewController whose behavior is slightly different. I'll try to adapt as much DonMag's code as possible to my use, but the idea by itself will greatly help me.

  • Related