Search code examples
iosobjective-cuitableviewlayoutcustom-cell

Custom cell for iOS app: XIB or coding?. Issues with height and frames positions


I'm trying to build a custom UITableCellView that will contain multiples subviews but right now I'm struggling with only two of them (the biggest ones): a UIImageView (I wouldn't mind to use UIWebView instead since the images are coming from internet) and a UITextView that should present all the text without scrolling, at once. With this scenario I started to build a custom cell using XIB file and subclassing UITableCellView (Autolayout disable) :

enter image description here

I have added two new properties (IBOutlet) to custom class (pretty simple):

@interface NewsFeedPostCell : UITableViewCell<UITextViewDelegate>
{
    UIImageView *picView;
    UITextView *postContent;
}

@property IBOutlet UIImageView *picView;
@property IBOutlet UITextView *postContent;

@end

and after that I'm using them to fill with data (I'm getting some stuff from iTunes that returns a beautiful JSON @"http://itunes.apple.com/search?term=ice%20age&country=us&entity=movie" ). For the moment I'm focused on showing data properly without getting exact sizes for each cell (apart from the size of the texts that are different) but I have lot of issues: content is not properly display because text is not all shown, first row doesn't show image, etc. I read a lot here at stackoverflow but I'm starting to feel pain about the many different ways that people solve it because I have tested also using only code to get it and I have had something similar or even worse.

My main question/complain here is what could be the best way to build a complex table with custom cells with different heights and subviews and how to calculate the sizes, or better than that, when and where (in the code) since heightForRowAtIndexPath is called before I have downloaded images to get their sizes. There are a lots of properties for layouts, redraw and "sizes-fitting" but any of those don't seem to work as I supposed they had to. I feel I'm too far to know how layout in iOS app works and seems to me that UI elements has no flexibility at all :(

This is source code used (by the way I'm using AFNetworking library in order to get images and load them into UIImageView):

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

    NSDictionary *post = [self.posts objectAtIndex:indexPath.row];
    NSString *postText = [post objectForKey:@"longDescription"];

    cell= (NewsFeedPostCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];

    if (cell == nil) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"NewsFeedCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];
    }

 CGRect picFrame = cell.picView.frame;
    picFrame = CGRectMake(100, 0, 300, 100);
    [cell.picView setFrame:picFrame];
    [cell.picView  setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[post objectForKey:@"artworkUrl100"]]]
                        placeholderImage:nil
                                 success:^(NSURLRequest *request , NSHTTPURLResponse *response , UIImage *image ){
                                     NSLog(@"Loaded successfully: %d", [response statusCode]);
                                     [cell.picView setImage:image];
                                     [cell.picView sizeToFit];

                                 }
                                 failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error){
                                     NSLog(@"failed loading: %@", error);
                                 }
     ];

CGSize stringSize = [self calculateTextHeight:postText];

    CGRect postFrame = cell.postContent.frame;
    postFrame = CGRectMake(10, 100, 300, stringSize.height);
    cell.postContent.frame = postFrame;

    cell.postContent.autoresizingMask = UIViewAutoresizingFlexibleHeight;

    cell.postContent.font = [UIFont systemFontOfSize:POST_CONTENT_FONT_SIZE];
    cell.postContent.text= postText;

    [cell.postContent setContentInset:UIEdgeInsetsZero];

    [cell.postContent sizeThatFits:cell.postContent.contentSize];


    return cell;
}

See issues in the screenshots (I'm using iOS simulator simulating an 3.5" retina device and using as target to build app iOS SDK 6.1)

First row (image is under top bar; you have to scroll to see it) This is first row

Another row that doesn't show text properly, I have to scroll down/up to get it: enter image description here

enter image description here

And it is impossible to get last row text complete: enter image description here


Solution

  • The best way to make custom cells with different heights is:

    make a NSMutableArray for cells:

    @property (nonatomic,retain)NSMutableArray* cellsArray;
    

    then in m.:

    the first method which call is

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

    make your cell here:

            -(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
                if (!self.cellsArray) {
    
                    self.cellsArray = [[NSMutableArray alloc]init];
    
                }
    
                ListCell* cell = [[ListCell alloc] initWithFrame:CGRectMake(0, 0,, 50)];
    
    
               // IMPLEMENT your custom cell here, with custom data, with custom,different height:
    
               // after add this cell to your array:
                [self.cellsArray addObject:cell];
    
               // IMPORTANT STEP:  set your cell height for the new height:
    
                cell.frame = CGRectMake(cell.frame.origin.x, cell.frame.origin.y, 303, yourLastItemInCell.frame.origin.y + yourLastItemInCell.frame.size.height);
    
    
                return cell.frame.size.height;
            }
    

    after you got the custom cells with different heights :

    #pragma mark - conform to delegates
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        return 1;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
        return 10;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    
        return self.cellsArray[indexPath.row];
    
    }
    

    I hope it helps !