iPeter
iPeter

Reputation: 1360

Expanding and Collapsing a tableView cell upto label's text

I have a label in a TableViewCell in which there are more than one lines of text. Initially on the label it shows only one line. I have a button on that cell. I want to expand the cell by clicking on the button upto the hight of the label's text.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   static NSString *CellIdentifier = @"tabCell";
   _cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

// Configure the cell...
   NSManagedObject *device = [self.persons objectAtIndex:indexPath.row];

   UILabel *nameLabel = (UILabel*)[_cell.contentView viewWithTag:2];
  nameLabel.text = [NSString stringWithFormat:@"%@", [device valueForKey:@"name"]];

   UILabel *dateLabel = (UILabel *)[_cell.contentView viewWithTag:3];
   dateLabel.text = [NSString stringWithFormat:@"%@",[device valueForKey:@"date"]];

   UILabel *descLabel = (UILabel *)[_cell.contentView viewWithTag:4];
//descTextView.text = [NSString stringWithFormat:@"%@",[device valueForKey:@"desc"]];


   UIImageView *personImage = (UIImageView *)[_cell.contentView viewWithTag:1];
   UIImage *personImg = [UIImage imageWithData:[device valueForKey:@"image"]];
   personImage.image = personImg;

    UIButton *viewMoreButton = (UIButton *)[_cell.contentView viewWithTag:5];
    [viewMoreButton addTarget:self
             action:@selector(myAction)
   forControlEvents:UIControlEventTouchUpInside];

    NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:[device valueForKey:@"desc"]
                                                                 attributes:@{ NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue" size:17]}];


    reqFrame=[attrString boundingRectWithSize:CGSizeMake(descLabel.frame.size.height, CGFLOAT_MAX)options:NSStringDrawingUsesLineFragmentOrigin
                                  context:nil];


    descLabel.attributedText = attrString;




    return _cell;
}

- (void)myAction{

   //what to write here?

}

Upvotes: 1

Views: 1432

Answers (3)

Bhanupriya
Bhanupriya

Reputation: 1202

you need to maintain two variables, just give tag to your button, and detect in action by its tag to reload that particular cell and another BOOL variable to detect if button touched. You should calculate height in heightForRowAtIndexPath method. I am posting code, it may help you

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

if(isReadMoreButtonTouched && [indexPath row]== indexOfReadMoreButton) {
    NSString *yourText = [arr1 objectAtIndex:indexPath.row]; // your text

    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                [UIFont fontWithName:@"Avenir Next" size:14], NSFontAttributeName,
                                [UIColor grayColor], NSForegroundColorAttributeName,
                                nil]; // set custom attributes

    NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:yourText attributes:attributes];

    CGRect paragraphRect = [attributedText boundingRectWithSize:CGSizeMake(625, CGFLOAT_MAX)
                                                        options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                        context:nil]; //here 625 is width of label

    NSLog(@"height = %f", paragraphRect.size.height);
    return paragraphRect.size.height;

}
else{

    return 200; //default height taken in storyboard
}
}


-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];

cell.lblKB.text = [arr objectAtIndex:indexPath.row];
cell.lblDetail.text = [arr1 objectAtIndex:indexPath.row];

NSString *yourText = [arr1 objectAtIndex:indexPath.row];
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
                            [UIFont fontWithName:@"Avenir Next" size:14], NSFontAttributeName,
                            GrayColor, NSForegroundColorAttributeName,
                            nil];   //your custom attributes

NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:yourText attributes:attributes];

CGRect paragraphRect = [attributedText boundingRectWithSize:CGSizeMake(625, CGFLOAT_MAX)
                                                    options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                    context:nil];

NSLog(@"height = %f", paragraphRect.size.height);

if (paragraphRect.size.height<200) {
    cell.btnMore.hidden = YES;
}
else{
    cell.btnMore.hidden = NO;
}

cell.btnMore.tag = indexPath.row;

return cell;
}


// action of button click

-(IBAction)MoreBtnClicked:(id)sender {

if (!isReadMoreButtonTouched) {
    isReadMoreButtonTouched = YES;
}
else{

    isReadMoreButtonTouched = NO;

}

indexOfReadMoreButton = [sender tag];

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[sender tag] inSection:0];
[self.tblKB reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; //reload that cell of your tableview

}

Upvotes: 0

Sauvik Dolui
Sauvik Dolui

Reputation: 5660

Anyhow need to get reference of the cell and indexPath on which the button is tapped in your myAction().

Create a private variable CGFloat newCellHeight; and initialize it to 0.0. Let reference to the associated cell is selectedCell and selected index path is indexPathOfTappedCell.

- (void)myAction{
        UILabel *descLabel = (UILabel*)[selectedCell.contentView viewWithTag:4];
        [descLabel sizeToFit]; // Automatically increases the height of the label as required
        newCellHeight = CGRectGetMaxY(descLabel.frame) + 10.0; // Extra padding 10.0
        [tableView reloadRowsAtIndexPaths:@[indexPathOfTappedCell] withRowAnimation:UITableViewRowAnimationAutomatic];
}

Now add the following TableView delegate method in your view controller

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (indexPath.section == indexPathOfTappedCell.section &&
        indexPath.row == indexPathOfTappedCell.row ) {
        return newCellHeight;
    }
    return 44.0; // Suppose default height is 44.0
}

Upvotes: 0

Misha
Misha

Reputation: 5380

First of all it is not a good practice to build cell in cellForRowAtIndexPath. Use willDisplayCell instead. See here why.

Secondly to do what you want you have to set desired height in heightForRowAtIndexPath. Once this accomplished, within your button selector call to refresh specific cells using

[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPathOfYourCell, nil] withRowAnimation:UITableViewRowAnimationAutomatic];

The implementation is similar:

- (void)buttonSelector
{
    myLabel.text = @"YOUR TEXT";
    [myLabel sizeToFit];
    [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPathOfYourCell, nil] withRowAnimation:UITableViewRowAnimationAutomatic];
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    ...
    return yourLabel.height;
}

Upvotes: 1

Related Questions