Expand UILabel inside UITableView with more button like Instagram

I have a project (which was written by other people) where there is a feed with content and text displayed inside a table view. Each post corresponds to one section in the table view, and each section has its own rows corresponding to elements such as content, text, button, etc.

I need to display a short label for more labels inside a table view cell, and when another button is clicked, the label will expand to whatever size the caption fits, everything happens inside the table cell. When the key is more pressed, I change the label property numberOfLines

to zero, and since the cells are auto-height all I need is to reload that particular header cell. (the cell is displayed correctly with an expanded size if I first set numberOfLines

to 0 before displaying the cell.)

I tried:

[tableView beginUpdates];

tableView endUpdates];

I've tried various animation options with:

[tableView reloadRowsAtIndexPaths:@[myPath] withRowAnimation:UITableViewRowAnimation(Bottom,Top,None etc)];

I tried:

[tableView reloadSections:[NSIndexSet indexSetWithIndex:myPath.section] withRowAnimation:UITableViewRowAnimation(Top,Bottom,None etc)];

But they all give the same result: the whole table view layout is confused: it jumps to another cell, some views are empty, the cells overlap each other, the video inside the cells stops playing, and the label does not expand (but is updated internally, for example, that short txt preview with one line animates top / bottom, etc but doesn't expand).

What could be causing the whole table view to be cluttered and how can I reload just one cell correctly and the expansion animation without messing up the whole layout? I have seen many questions and answers about this, but they all recommend options that I have already tried and explained above.

My target apps iOS 8.0+

UPDATE: Here is the relevant code (with some parts related to the inner workings that are not related to layout removed):

MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier: MyCellIdentifier forIndexPath:indexPath];
cell.delegate = self;
cell.indexPathToReloadOnAnimation = indexPath;
cell.shouldShortenCaption = YES;

id post = self.posts[indexPath.section] ;
[cell setPost:post];

return cell;

      

And inside setPost:

:

if(self.shouldShortenCaption){
    captionLabel.numberOfLines = 2;
}else{
    captionLabel.numberOfLines = 0;
}
NSString *text = [some calculated (deterministic) text from post object];

      

The button action is simple:

self.shouldShortenCaption = NO;
[one of the reload codes that I've written above in the question]

      

UPDATE 2: Here are some more ways to fix the problem:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    if (section < self.posts.count) {
        return 59;
    }else
        return 0;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    if (section < self.posts.count) {
        MyFeedHeader *header = [tableView dequeueReusableCellWithIdentifier:MyFeedHeaderIdentifier];
        header.delegate = self;
        [header setPostIndex:section];
        [header setPost:self.posts[section]] ;

        return header;
    }
    else
        return nil;
}

      

The header method setPost:

basically sets the appropriate texts on the labels (which have nothing to do with the caption, they are completely different cells. The problematic cell is not a header cell). There are no footer methods in the table. The only method with respect to height is the one above.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section >= self.posts.count) {
        return 1;
    }
    id post = self.posts[section];
    [calculate number of rows, which is deterministic]
    return [number of rows];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    BOOL hasCursor = self.cursor && self.hasMore ? 1 : 0;
    return self.posts.count + hasCursor;
}

      

(The number of messages and the cursor and hasMore are also deterministic).

UPDATE 3: I asked a question (which was not a duplicate, although there are similar questions) and got a helpful answer that solved my problem. Can downvoters think through the reason they were suspended?

+3


source to share


1 answer


Here's an example: https://github.com/DonMag/DynamicCellHeight

Table B is one way to achieve Over / Under (Table A was for another layout I played with). It uses a method [tableView beginUpdates]; tableView endUpdates];

to start rebuilding the table.

The key has configured all of your constraints correctly, so the Auto-Layout mechanism does what you expect.

The example is in Swift, but needs to be easily translated back to Obj-C (I think I did it in Obj-C in the first place).

enter image description here



Edit: some additional notes ...

This is using the fairly standard method of dynamic height table cells. Vertical spacing constraints between elements effectively "push" cell boundaries. The tap here toggles the numberOfLines

label property between 2 and 0 (zero means as many lines as needed). Consecutive calls to beginUpdates

/ endUpdates

in the table view tell the auto layout engine to recalculate the row height without having to reload the data.

In this example, I used a little "trick" to get the smoothing / smoothing effect. The multiline label you see here is contained in UIView

(with clipsToBounds

true). There is a second duplicate multiline label (alpha 0 so not visible) that controls the height. I found that the change numberOfLines

on the visible sorting label was "anchored" to two lines, and then the resize animation occurred ... resulting in the text "jumping".

I just added a "not so good" version to my GitHub repository for comparison.

enter image description here

+8


source







All Articles