I am trying to use AutoLayout inside a UITableViewCell with Objective-C. I am not using a nib/xib/storyboard. I create my views in code.
Here's my UITableViewCell:
@implementation SettlementTableViewCell
- (instancetype) initWithReuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
if (!self) return nil;
[self setSelectionStyle:UITableViewCellSelectionStyleNone];
_order = [[UILabel alloc] init];
[_order setTranslatesAutoresizingMaskIntoConstraints:NO];
[_order setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]];
[[self contentView] addSubview:_order];
_amount = [[UILabel alloc] init];
[_amount setTranslatesAutoresizingMaskIntoConstraints:NO];
[_amount setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]];
[_amount setTextAlignment:NSTextAlignmentRight];
[[self contentView] addSubview:_amount];
_pickupDate = [[UILabel alloc] init];
[_pickupDate setTranslatesAutoresizingMaskIntoConstraints:NO];
[_pickupDate setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]];
[[self contentView] addSubview:_pickupDate];
_pickupLocation = [[UILabel alloc] init];
[_pickupLocation setTranslatesAutoresizingMaskIntoConstraints:NO];
[_pickupLocation setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]];
[_pickupLocation setAdjustsFontSizeToFitWidth:YES];
[_pickupLocation setTextAlignment:NSTextAlignmentRight];
[[self contentView] addSubview:_pickupLocation];
_deliveryDate = [[UILabel alloc] init];
[_deliveryDate setTranslatesAutoresizingMaskIntoConstraints:NO];
[_deliveryDate setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]];
[[self contentView] addSubview:_deliveryDate];
_deliveryLocation = [[UILabel alloc] init];
[_deliveryLocation setTranslatesAutoresizingMaskIntoConstraints:NO];
[_deliveryLocation setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]];
[_deliveryLocation setAdjustsFontSizeToFitWidth:YES];
[_deliveryLocation setTextAlignment:NSTextAlignmentRight];
[[self contentView] addSubview:_deliveryLocation];
[self setNeedsUpdateConstraints];
return self;
}
- (void) updateConstraints {
[super updateConstraints];
UIEdgeInsets padding = UIEdgeInsetsMake(5, 20, -5, -20);
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_order attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationLessThanOrEqual
toItem:[self contentView] attribute:NSLayoutAttributeLeft multiplier:1 constant:padding.left]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_order attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
toItem:[self contentView] attribute:NSLayoutAttributeTop multiplier:1 constant:padding.top]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_amount attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
toItem:[self contentView] attribute:NSLayoutAttributeTop multiplier:1 constant:padding.top]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_amount attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
toItem:[self contentView] attribute:NSLayoutAttributeRight multiplier:1 constant:padding.right]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_pickupDate attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
toItem:[self contentView] attribute:NSLayoutAttributeLeft multiplier:1 constant:padding.left]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_pickupDate attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
toItem:_order attribute:NSLayoutAttributeBottom multiplier:1 constant:padding.top]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_pickupLocation attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
toItem:_pickupDate attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_pickupLocation attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:_pickupDate attribute:NSLayoutAttributeRight multiplier:1.0 constant:2]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_pickupLocation attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
toItem:[self contentView] attribute:NSLayoutAttributeRight multiplier:1 constant:padding.right]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_deliveryDate attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
toItem:[self contentView] attribute:NSLayoutAttributeLeft multiplier:1 constant:padding.left]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_deliveryDate attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
toItem:_pickupDate attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_deliveryDate attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual
toItem:[self contentView] attribute:NSLayoutAttributeBottom multiplier:1 constant:padding.bottom]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_deliveryLocation attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
toItem:_deliveryDate attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_deliveryLocation attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual
toItem:[self contentView] attribute:NSLayoutAttributeBottom multiplier:1 constant:padding.bottom]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_deliveryLocation attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:_deliveryDate attribute:NSLayoutAttributeRight multiplier:1.0 constant:2]];
[[self contentView] addConstraint:[NSLayoutConstraint constraintWithItem:_deliveryLocation attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
toItem:[self contentView] attribute:NSLayoutAttributeRight multiplier:1 constant:padding.right]];
// [_order setBackgroundColor:[UIColor redColor]];
// [_amount setBackgroundColor:[UIColor orangeColor]];
// [_pickupDate setBackgroundColor:[UIColor yellowColor]];
// [_pickupLocation setBackgroundColor:[UIColor greenColor]];
// [_deliveryDate setBackgroundColor:[UIColor blueColor]];
// [_deliveryLocation setBackgroundColor:[UIColor purpleColor]];
}
@end
Here's the UIViewController:
@interface Settlement : NSObject
@property (nonatomic, strong) NSString *orderId;
@property (nonatomic, strong) NSString *amount;
@property (nonatomic, strong) NSString *pickupDate;
@property (nonatomic, strong) NSString *deliveryDate;
@property (nonatomic, strong) NSString *pickupLocation;
@property (nonatomic, strong) NSString *deliveryLocation;
@end
@implementation Settlement
@end
@interface SettlementsViewController () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) NSMutableArray *rows;
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation SettlementsViewController
- (instancetype) init {
self = [super init];
if (!self) return nil;
[self setTitle:@"Settlements"];
_rows = [[NSMutableArray alloc] initWithCapacity:5];
Settlement *set = [[Settlement alloc] init];
[set setOrderId:@"01234567"];
[set setAmount:@"$9999.99"];
[set setPickupDate:@"02/23/2015 0800"];
[set setDeliveryDate:@"02/25/2015 1100"];
[set setPickupLocation:@"Point Field Landing on the Severn, MD"];
[set setDeliveryLocation:@"Winchester-on-the-Severn, MD"];
[_rows addObject:set];
set = [[Settlement alloc] init];
[set setOrderId:@"0006181"];
[set setAmount:@"$3.42"];
[set setPickupDate:@"12/26/2013 1040"];
[set setDeliveryDate:@"02/13/2014 0800"];
[set setPickupLocation:@"Irondale, AL"];
[set setDeliveryLocation:@"Lithonia, GA"];
[_rows addObject:set];
set = [[Settlement alloc] init];
[set setOrderId:@"0002586"];
[set setAmount:@"$1.66"];
[set setPickupDate:@"09/27/2012 1350"];
[set setDeliveryDate:@"02/09/2013 1115"];
[set setPickupLocation:@"Decatur, AL"];
[set setDeliveryLocation:@"Birmingham, AL"];
[_rows addObject:set];
set = [[Settlement alloc] init];
[set setOrderId:@"0002586"];
[set setAmount:@"$41.22"];
[set setPickupDate:@"11/08/2013 1608"];
[set setDeliveryDate:@"11/11/2013 0000"];
[set setPickupLocation:@"Birmingham, AL"];
[set setDeliveryLocation:@"Simi Valley, CA"];
[_rows addObject:set];
set = [[Settlement alloc] init];
[set setOrderId:@"0002586"];
[set setAmount:@"$41.22"];
[set setPickupDate:@"11/08/2013 1608"];
[set setDeliveryDate:@"11/11/2013 0000"];
[set setPickupLocation:@"Birmingham, AL"];
[set setDeliveryLocation:@"Simi Valley, CA"];
[_rows addObject:set];
return self;
}
- (void) loadView {
[super loadView];
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
[_tableView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
[_tableView setDelegate:self];
[_tableView setDataSource:self];
[_tableView setEstimatedRowHeight:72.0f];
[_tableView setRowHeight:UITableViewAutomaticDimension];
[[self view] addSubview:_tableView];
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return _rows.count; }
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
SettlementTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (!cell) cell = [[SettlementTableViewCell alloc] initWithReuseIdentifier:@"cell"];
Settlement *settlement = [_rows objectAtIndex:indexPath.row];
[[cell order] setText:[settlement orderId]];
[[cell amount] setText:[settlement amount]];
[[cell pickupDate] setText:[settlement pickupDate]];
[[cell deliveryDate] setText:[settlement deliveryDate]];
[[cell pickupLocation] setText:[settlement pickupLocation]];
[[cell deliveryLocation] setText:[settlement deliveryLocation]];
return cell;
}
@end
When the screen first loads, I get this layout:
When I change to landscape, I get:
When I switch back to portrait, I get:
This last state is the layout I really want. How can I make the initial layout look like the one post-orientation change? What am I missing?
This was as short of an example as I could make. I can provide a running project that exhibits the issue, but I don't know the best way to do that. Leave a comment telling me how and I'll put it out there.
Thanks!
I continued to play with this. I get the layout I want if I set the width explicitly on both of the date fields:
Can anyone explain why the intrinsic content size isn't good enough? Thanks!