Wednesday, August 8, 2012

Creating Dyanamic UITableViewCell Height

  Creating Dyanamic UITableViewCell Height

This sample code shows how we can create uitableviewcell height dynamically based on the text it consists.
Let assume we have UILabel in cell which contains some text, and code below  creates the appropriate cell in tableview depending on the label size :

1. Lets define some constants for the program:
      #define FONT_SIZE 14.0f
      #define CELL_CONTENT_WIDTH  305.0f
      #define CELL_CONTENT_MARGIN  8.0f

2. Return the height of each cell depending on its label size : 

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
        NSString *text =@"Read your text for each cell here (from Array or Dictionary)";
         // calculating the size of the text/string
        CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
 
         // Calculating the height of cell
              CGFloat height = MAX(size.height, 44.0f);
              return height + (CELL_CONTENT_MARGIN * 2);

}

3.  Now lets create cell having UILabel init:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
   
    static NSString *CellIdentifier = @"Cell";
     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
    }
// Below two line code will insure that there will be no overlapping/blurr of custom views created inside cell
    for (UIView * view in cell.contentView.subviews) {
        [view removeFromSuperview];
    }


          NSString *text = @"Read your text for each cell here (from Array or Dictionary)";
          UILabel *descriptionLabel = [[UILabel alloc] initWithFrame: CGRectMake(10, 8, 278, 40)];
          // 40 choose the height of label double of normal label size
           descriptionLabel.adjustsFontSizeToFitWidth = NO;
           descriptionLabel.text = text;
             [cell.contentView addSubview:descriptionLabel];
             [descriptionLabel setNumberOfLines:0];
           CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
           CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
           [descriptionLabel setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];

 return cell;
   
}

4 comments:

  1. That was of great help thanks :)

    ReplyDelete
  2. well i am having a problem. I am using two custom table cells in one table as in "wechat" each for receiver and sender design, i.e.
    - sender's nib with his/her photo in right and message in left, and
    - receiver's nib with his/her photo in right and message in right.

    Until I was using your above code in single custom table cell it worked fine and it is still working fine for sender but in receiver end there is only two lines of message with (...) and the rest of the message is not there. Both the custom table cell has almost same code as above as required. Is there something I am missing? Thanks in advance

    ReplyDelete
    Replies
    1. Hello Prayas,
      Sorry for late reply. I couldn't manage my time for your issue. As far as your issue, since it is related to your two Nib file mixed up, to make the correction i need to track the actual code , i need to know from where exactly problem is occuring. Without seeing the actual problem i can not give you any comments as it may lead to another problem.

      But here is my alternative suggestion :
      Why don't you work on single cell , don't create any extra UITableViewCell object, just work on your TableView default cell. Here is my hint :
      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

      static NSString *CellIdentifier = @"Cell";
      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
      if (cell == nil) {
      cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
      }
      // Below two line code will insure that there will be no overlapping/blurr of custom views created inside cell
      for (UIView * view in cell.contentView.subviews) {
      [view removeFromSuperview];
      }
      // create your msgTExt and Profile pic objects
      // By default create msgTextLbl on Right frame, Pic on Left Frame
      // UILabel *msgLbl =
      // UIImageView *profileView=
      // [cell.contentView addSubview: msgLbl];
      // [cell.contentView addSubView: profileView];

      // Now check whther message is by you or not
      if( [[NSString stringWithFormat:@"%@",chatObj.name] isEqualToString:@"You"]){
      // If message is yours then shift/change the MSgLbl and ProfileImgView position
      // MsgLbl to the left and profileImgView to the right
      //for eg: MsgLbl.frame = change frame
      // profileImgView.frame = frame position you decide
      }
      }

      Delete
    2. Hi Sameer,

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


      chat *chatObj = [self.chats objectAtIndex:indexPath.row];


      if( [[NSString stringWithFormat:@"%@",chatObj.name] isEqualToString:@"You"]){
      static NSString *simpleTableIdentifier = @"chatTableCell";
      chatTableCell *cell = [tableView1 dequeueReusableCellWithIdentifier:simpleTableIdentifier];
      if (cell == nil)
      {
      NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"chatTableCell" owner:self options:nil];
      cell = [nib objectAtIndex:0];
      }

      cell.nameLabel.text = chatObj.name;
      NSString *imageFile = [[NSBundle mainBundle] pathForResource:@"user" ofType:@"png"];
      UIImage *image = [[UIImage alloc]initWithContentsOfFile:imageFile];

      cell.thumbnailImageView.image = image;
      cell.chatLabelTest.text = chatObj.message;
      cell.chatLabelTest.numberOfLines = 0;
      CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
      CGSize size = [chatObj.message sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
      [cell.chatLabelTest setFrame:CGRectMake(cell.chatLabelTest.frame.origin.x, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), (size.height + 60))];

      //[cell.chatLabelTest sizeToFit];
      return cell;
      }
      else{
      static NSString *simpleTableIdentifier = @"chatTableCell2";
      chatTableCell *cell = [tableView1 dequeueReusableCellWithIdentifier:simpleTableIdentifier];
      if (cell == nil)
      {
      NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"chatTableCell2" owner:self options:nil];
      cell = [nib objectAtIndex:0];
      }
      chat *chatObj = [self.chats objectAtIndex:indexPath.row];
      cell.nameLabel.text = chatObj.name;
      NSString *imageFile = [[NSBundle mainBundle] pathForResource:@"admin" ofType:@"png"];
      UIImage *image = [[UIImage alloc]initWithContentsOfFile:imageFile];

      cell.thumbnailImageView.image = image;
      cell.chatLabelTest.text = chatObj.message;
      cell.chatLabelTest.numberOfLines = 0;
      CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
      CGSize size = [chatObj.message sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
      [cell.chatLabelTest setFrame:CGRectMake(cell.chatLabelTest.frame.origin.x, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), (size.height + 60))];

      //[cell.chatLabelTest sizeToFit];
      return cell;
      }


      }

      this is the code I used , first nib file and second nib file has custom design so I cannot use default design of ios in my case, and this code works as I want, the first nib i.e in case of "you" it works perfectly fine with message length as long as I want but in case of second nib in else condition, the design works great for small messages the text display is also good, but when it comes to long text baam it only shows two lines with (...) , but height of the cell is maintained by the code above meaning if it a short message then the height of the cell is small as required by text and in case of long text the height is long, only the message is of two lines with (...) , and I also found that after several messages on srolling up and down sometimes it shows the whole of the message without (...) full long message. I am not sure where the problem lies.
      The project I am working is something I cannot share right now but I guess I can make a sample of it after few days with only my problem.
      Thanks of the reply :)

      Delete