AntonBoer AntonBoer - 1 year ago 75
Objective-C Question

UIView's autolayout size reported from wrong size class the first time

I have a UITableViewController with some custom cells and an UIView within each cell. I have implemented the controller's cellForRowAtIndexPath to configure the UIView in each cell. For this purpose I need to know the width of the UIView on screen. Since I am using autolayout and size classes to automatically change the size of the UIView based on device orientation, I have implemented an additional method of getting the width runtime.

The problem is that when the table view is presented the first time, my code reports width for UIVIew from a compact width size class even when I am using the device in the landscape orientation. The system renders all the views as should, but my code to get the width is not working. Scrolling new cells visible or an orientation change will remedy the situation immediately.

My code:

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

// ...

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

if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
cell = [nib firstObject];
} else {

// Clear custom content

NSArray *viewsToRemove = [cell.histogramView subviews];
for (UIView *v in viewsToRemove) {
[v removeFromSuperview];

[cell setNeedsLayout];
[cell layoutIfNeeded];

int width = ((CustomView*)cell.customView).getWidth;
NSLog(@"width = %d", width);

// ...


And then:

@implementation CustomView

- (int)getWidth {
[self setNeedsLayout];
[self layoutIfNeeded];

int width = self.frame.size.width;
return width;


Edited to add:

The problem seems to be that at when cellForRowAtIndexPath is called the first time tableview appears, autolayout has not occurred for the cell. Forcing it with [cell setNeedsLayout] and [cell layoutIfNeeded] right after creating the cell does not do the trick either.

It seems my problem root cause is a potential duplicate of How to know the width of an UITableViewCell when using auto layout? So the problem has to do with fact that when my CustomCell is loaded from a nib, it will have the default frame. Special tricks should be done to force autolayout. However, the accepted answer does not work for cells that are initially out of visible area. Any takers on this?

Answer Source

I found out the correct solution to this:

  1. Create a custom cell like I in the original question.
  2. Set cell.contentMode = UIViewContentModeRedraw in tableview: cellForRowAtIndexPath:
  3. Implement layoutSubviews for the custom cell like so:

    - (void)layoutSubviews { [super layoutSubviews]; NSLog(@"cell width == %f", self.bounds.size.width); }

This way you will have access to the size of the cell as it will appear on screen.