1

I'm parsing a JSON string into a custom table view cell. How can I resize the label's height to fit the content text and also resize the cell to fit it's content.

The code:

#import "DEMOSecondViewController.h"
#import "DEMONavigationController.h"
#import "PostsObject.h"
#import "RNBlurModalView.h"
#import "AFNetworking.h"

@interface DEMOSecondViewController ()

@end

@implementation DEMOSecondViewController
@synthesize tableView = _tableView, activityIndicatorView = _activityIndicatorView, movies = _movies;

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.title = @"iCelebri.com";
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Menu"
                                                                             style:UIBarButtonItemStylePlain
                                                                            target:(DEMONavigationController *)self.navigationController
                                                                            action:@selector(showMenu)];

    self.tableView.separatorColor = [UIColor clearColor];

    // Setting Up Activity Indicator View
    self.activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    self.activityIndicatorView.hidesWhenStopped = YES;
    self.activityIndicatorView.center = self.view.center;
    [self.view addSubview:self.activityIndicatorView];
    [self.activityIndicatorView startAnimating];
    self.tableView.separatorColor = [UIColor clearColor];

    // Initializing Data Source
    self.movies = [[NSArray alloc] init];

    [self makeConnection];

}

-(void)makeConnection {
    _url = [[NSURL alloc] initWithString:@"my-site.com/json.php?name=Name"];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:_url];

    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        self.movies = JSON;
        [self.activityIndicatorView stopAnimating];
        [self.tableView reloadData];

    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        NSLog(@"Request Failed with Error: %@, %@", error, error.userInfo);
    }];

    [operation start];
}

// Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (self.movies && self.movies.count) {
        return self.movies.count;
    } else {
        return 0;
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 124;
}

- (void)tableView:(UITableView *)tableView
  willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [cell setBackgroundColor:[UIColor clearColor]];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *simpleTableIdentifier = @"PostsObject";

    PostsObject *cell = (PostsObject *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    if (cell == nil)
    {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"PostsObject" owner:self options:nil];
        cell = [nib objectAtIndex:0];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background.png"]];

        self.tableView.backgroundView = imageView;
    }

    NSDictionary *movie = [self.movies objectAtIndex:indexPath.row];
    cell.title.text = [movie objectForKey:@"message"];
    cell.published.text = [movie objectForKey:@"published"];

    return cell;
}


@end

So I want the cell to resize to the size of the title label plus text label "message": [movie objectForKey:@"message"];

How can I do this?

Refael.S
  • 1,634
  • 1
  • 12
  • 22
tracifycray
  • 1,403
  • 4
  • 18
  • 27
  • possible duplicate of [Xcode - UILabel - auto-size label to fit text?](http://stackoverflow.com/questions/8796862/xcode-uilabel-auto-size-label-to-fit-text) – nhgrif Nov 17 '13 at 17:21
  • Use the help of this link: http://stackoverflow.com/questions/9827126/change-the-uitableviewcell-height-according-to-amount-of-text And add to the code of the answer the method heightForRow... And return hight according to the label height – Refael.S Jan 07 '14 at 10:31
  • Also use the help of this:http://stackoverflow.com/questions/1012361/resize-uitableviewcell-to-the-labels-height-dynamically – Refael.S Jan 07 '14 at 10:37

3 Answers3

1

This Is a full code for resizing the cell's height according to the text length for each indexPath:

The .h file:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
    IBOutlet UITableView *_tableView;
    UIActivityIndicatorView *_activityIndicatorView;
    NSArray *_movies;
    CGFloat cellTextWidth;
    CGFloat cellHeightExceptText;
}
@property (nonatomic, retain) UIFont *fontForCellText;
@property (nonatomic, retain) UITableView *tableView;
@property (nonatomic, retain) UIActivityIndicatorView *activityIndicatorView;
@property (nonatomic, retain) NSArray *movies;

@end

The .m file:

#import "ViewController.h"
#import "AFNetworking.h"
#import "ParseFeedCell.h"

@interface ViewController ()

@end

@implementation ViewController
@synthesize tableView = _tableView, activityIndicatorView = _activityIndicatorView, movies = _movies;
@synthesize fontForCellText;

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ParseFeedCell" owner:self options:nil];
    ParseFeedCell *cell = [nib objectAtIndex:0];
    fontForCellText = cell.title.font;
    cellTextWidth = cell.title.frame.size.width;
    cellHeightExceptText = cell.frame.size.height - cell.title.frame.size.height;

    [self.navigationController setNavigationBarHidden:YES];

    self.tableView.separatorColor = [UIColor clearColor];

    // Setting Up Activity Indicator View
    self.activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    self.activityIndicatorView.hidesWhenStopped = YES;
    self.activityIndicatorView.center = self.view.center;
    [self.view addSubview:self.activityIndicatorView];
    [self.activityIndicatorView startAnimating];
    self.tableView.separatorColor = [UIColor clearColor];

    // Initializing Data Source
    //self.movies = [[NSArray alloc] init];

    NSURL *url = [[NSURL alloc] initWithString:@"your-website.com/json_file?name=Name"];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];

    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        self.movies = [[NSArray alloc] initWithArray:JSON];
        [self.activityIndicatorView stopAnimating];
        [self.tableView reloadData];

    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        NSLog(@"Request Failed with Error: %@, %@", error, error.userInfo);
    }];

    [operation start];
}

// Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (self.movies && self.movies.count) {
        return self.movies.count;
    } else {
        return 0;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *simpleTableIdentifier = @"ParseFeedCell";

    ParseFeedCell *cell = (ParseFeedCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    if (cell == nil)
    {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ParseFeedCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;

    }

    NSDictionary *movie = [self.movies objectAtIndex:indexPath.row];
    NSString *strText = [movie objectForKey:@"message"];

    CGRect rect = cell.title.frame;
    rect.size.height = [self getHeightForText:strText];
    cell.title.frame = rect;
    cell.title.text = strText;
    cell.arrow.center = CGPointMake(cell.arrow.frame.origin.x, rect.origin.y + rect.size.height/2);
    cell.published.text = [movie objectForKey:@"published"];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary *movie = [self.movies objectAtIndex:indexPath.row];
    NSString *strText = [movie objectForKey:@"message"];

    CGFloat cellHeight = cellHeightExceptText + [self getHeightForText:strText];

    return cellHeight;
}

- (CGFloat)getHeightForText:(NSString *)strText
{
    CGSize constraintSize = CGSizeMake(cellTextWidth, MAXFLOAT);
    CGSize labelSize = [strText sizeWithFont:fontForCellText constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping];
    NSLog(@"labelSize.height = %f",labelSize.height);
    return labelSize.height;
}

Make sure that the Autolayout for your custom cell "ParseFeedCell" is off (Not Checked):

Autolayout

Also change the number of Lines of the text UILabel to 999999 so it's not limited to lines. I am sure that with a bit of research you can find a way to know how many lines the text is and assign the lines to the UILabel programatically.

Refael.S
  • 1,634
  • 1
  • 12
  • 22
1

Use this to a dynamic sized cell:

Start by defining the following:

#define FONT_SIZE 13.0f 
#define CELL_CONTENT_WIDTH 290.0f 
#define CELL_CONTENT_MARGIN 19.0f 
  1. Implement the following helper method;

     -(CGSize)frameForText:(NSString*)text sizeWithFont:(UIFont*)font constrainedToSize:(CGSize)size  {
    
    NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
    paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
    
    NSDictionary * attributes = @{NSFontAttributeName:font,
                                  NSParagraphStyleAttributeName:paragraphStyle
                                  };
    
    
    CGRect textRect = [text boundingRectWithSize:size
                                         options:NSStringDrawingUsesLineFragmentOrigin
                                      attributes:attributes
                                         context:nil];
    
    
    // This contains both height and width, but we really care about height.
    return textRect.size;
    }
    
  2. In your UITableViewDelegate Height method:

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
    {
    
    NSDictionary *movie = [self.movies objectAtIndex:indexPath.row];
    
            NSString *text = [movie objectForKey:@"message"];        
    
            CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
    
            CGSize size = [self frameForText:text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint];
    
            CGFloat height = MAX(size.height, 14.0f);
    
            return height + CELL_CONTENT_MARGIN;
    
    
    }
    
  3. Set the frame and text in your UITableViews cellForRowAtIndexPath:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *simpleTableIdentifier = @"PostsObject";
    
    PostsObject *cell = (PostsObject *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    if (cell == nil)
    {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"PostsObject" owner:self options:nil];
        cell = [nib objectAtIndex:0];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background.png"]];
    
        self.tableView.backgroundView = imageView;
    }
    
    NSDictionary *movie = [self.movies objectAtIndex:indexPath.row];
    
    NSString *text = [movie objectForKey:@"message"];
    
    
        CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
    
    
        CGSize size = [self frameForText:text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint];
    
        cell.txtLabel.text = text;
        cell.txtLabel.frame = CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 14.0f));
    
    cell.published.text = [movie objectForKey:@"published"];
    
    return cell;
    }
    
0

If you want the cell to resize based on the content of the JSON you have to change the following method:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 124;
}

You're setting the height of each cell to 124px. What you should do instead it's to:

  1. Get the size of the string rendered with the specified constraints.
  2. Reset the frame of the label that contains the string
  3. Return the right size for the cell in tableView:heightForRowAtIndexPath:

Hope it helps! Cheers

ubiAle
  • 445
  • 9
  • 19