3

In a UITableView, I add content to my cells via UILabels.

To define the optimal size (as large as allowed by the cell's width) I noticed that only tableView.contentSize.width was reliable, because cell.contentView.bounds gives always a portrait width, even in landscape

This works very well in couple with autoresizingMask: when I switch from Portrait to Landscape and again to Portrait.

Problems come when I load my View directly in Landscape. The width of my UILabels is larger than the screen, even if a breakpoint shows me a correct width for tableView.contentSize.width

Switching between landscape and portait changes nothing, the width is still larger than the screen.

If I don't use autoresizingMask, the width is correct, if I use it, even with a short text it goes out of the screen (but I notice it only thanks to a test background color or with using very large NSString).

In brief:

  • portrait > landscape > portrait > landscape... is fine (resize perfectly)
  • landscape > portrait > landscape > portrait... bugs (width outrange)

My code simplified:

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

    //[...]
    UIFont *font = [UIFont fontWithName:@"Helvetica-Bold" size:12.0];
    CGRect frame = CGRectMake(cell.contentView.bounds.origin.x + 20,
                                  cell.contentView.bounds.origin.y + 4,
                                  tableView.contentSize.width - 50,
                                  font.lineHeight);

      //at this point a breakpoint shows that frame is whatever I asked (ex: 200 for test)
      //but still the labels is wider than the screen
    UILabel *result = [[[UILabel alloc] initWithFrame:frame] autorelease];
    [result setText:@"bouh!"];
    result.lineBreakMode = UILineBreakModeWordWrap;
    result.numberOfLines = 1;
    result.font = font;

      //if I comment this line, the width is always what I want
    result.autoresizingMask = UIViewAutoresizingFlexibleWidth;

      //test to see the real size
    result.backgroundColor = [UIColor orangeColor];

    [cell.contentView addSubview:result];
    //[...]
    return cell;
}

I'm asking your help here in order to see if there's a better way to do what I wanted? if not, what am I doing wrong?

chriscatfr
  • 2,592
  • 3
  • 24
  • 32

3 Answers3

3

I could not find a clean easy universal solution (adaptable to every screen).

But here is what I did to make it work:

    //in portrait cell width works fine with autoResize
    //in landscape tableView width works fine with autoResize
CGFloat cellWidth;

if ( [UIDevice currentDevice].orientation != UIDeviceOrientationLandscapeLeft
    && [UIDevice currentDevice].orientation != UIDeviceOrientationLandscapeRight)
  {
    cellWidth = tableView.contentSize.width;
  }
else
  {
    cellWidth = cell.contentView.bounds.size.width;
  }

And so, later in the code I use it that way:

CGRect frame = CGRectMake(cell.contentView.bounds.origin.x + 20,
                                  cell.contentView.bounds.origin.y + 4,
                                  cellWidth - 50,
                                  font.lineHeight);
UILabel *result = [[[UILabel alloc] initWithFrame:frame] autorelease];

But something was weird: I needed to use always tableView.contentSize.width for the frame of my Activity Indicators because cell.contentView.bounds.size.width was only 320 even in Landscape

CGRect activityIndicatorRect =
CGRectMake(
           cell.contentView.bounds.origin.x + tableView.contentSize.width - 60 ,
           cell.contentView.bounds.origin.y + 17,
           30, 30);
chriscatfr
  • 2,592
  • 3
  • 24
  • 32
1

What I tend to do is subclass UITableViewCell and then override the initWithReuseIdentifier...

- (id)initWithReuseIdentifier:(NSString *)reuseIdentifier  {        
    self = [super initWithReuseIdentifier:reuseIdentifier];

    if (self != nil) {
        [self setFrame:CGRectMake(0.0, 0.0, kLayoutWidth, kLayoutHeight)];

        // Set up labels, buttons etc....
    }
}

kLayoutWidth and kLayoutHeight are defines you can set to arbitrary values, you can put the values directly in the CGRect but I prefer to have sizes specified at the top of the class as compiler defines.

The beauty of this is that now you can layout your cell in a fixed size and set autoresizing masks for the content elements, and when the tableview resizes the cell it will all resize correctly.

Simon Lee
  • 22,304
  • 4
  • 41
  • 45
  • so it means you set the Width and Height once and for all? What I was trying to do was to be adaptable to every screen, even some not existing yet. But at last with your solution the cell stop giving a wrong width value – chriscatfr May 25 '11 at 06:09
  • No what I mean is that you lay out the cell when it is a known size, set all of your autoresizing masks then it doesn't matter what size the cell becomes it should all resize correctly. The issue is in the fact that initially the cell MAY be different sizes in landscape / portrait, by setting the size yourself and layout out you ensure the layout is as required. – Simon Lee May 25 '11 at 08:26
  • sorry if I'm slow to validate your answer. As soon as I tested it, I'll reply. It seems to be a good idea and my ugly Labels needs a solution. – chriscatfr May 26 '11 at 09:01
0

You can also use different nibs for Portrait/Landscape/iPhone/iPad and load them accordingly. Saves you lots of code

static NSString *aCustomCellIdentifier = @"aCustomCell";

CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:aCustomCellIdentifier];

if (!cell)
{
    if (!IS_IPAD)
        cell = [[[UINib nibWithNibName:@"CustomCell" bundle:nil] instantiateWithOwner:self options:nil] lastObject];
    else
        cell = [[[UINib nibWithNibName:@"CustomCell_iPad" bundle:nil] instantiateWithOwner:self options:nil] lastObject];

}
biggee
  • 1
  • 1
    we did use different views for portrait/landscape but different nibs seems like overkill to me... – BBog Oct 02 '12 at 14:21