Reputation: 3101
Basically, I create an empty UITableViewCell in separate XIB file. Hierarchy is shown here: https://www.dropbox.com/s/nba8e5t7dvti7os/hierarchy.png
I want to change height of my inner view at runtime based on content (by updating constraint constant) and based on this calculate cell/row height. So, if I have tall content, my row expands, if I have short content, my row becomes smaller. I want to use AutoLayout for these calculations.
I have constraints to stick to top/bottom of ContentView and want my inner view to have Height =20.
And almost immediately I see a conflict: https://www.dropbox.com/s/b3effgdw3t2768m/conflict.png
Most definitely my understanding of AutoLayout is not complete.
1st question is: how is that wrong that I want my view to be 20pt height and my ContenView to be exactly the same size?
2nd question is: how do I achieve that?
Upvotes: 0
Views: 628
Reputation: 11607
Here's a demo app I've hacked up for you, done purely with code.
You'll see in my DemoTableViewCell.m file, the constraints I've used doesn't have a fixed height constraint, to allow the content to freely expand. It's pinned to the four contentView edges (top, right, bottom, left) with an optional 20 pixel padding for visual formatting purpose.
The result is this:
#import "AppDelegate.h"
#import "DemoViewController.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
DemoViewController *demoVC = [[DemoViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:demoVC];
self.window.rootViewController = navController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
#import <UIKit/UIKit.h>
@interface DemoViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) NSArray *arrText;
@property (nonatomic, strong) UITableView *tableView;
@end
#import "DemoViewController.h"
#import "DemoTableViewCell.h"
@interface DemoViewController ()
{
DemoTableViewCell *offscreenCell;
}
@end
@implementation DemoViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationItem.title = @"Dynamic Cell Height";
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
// init data source
self.arrText = @[
@"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
@"Cras rhoncus velit odio, quis dapibus orci tristique eget. Aenean pretium lorem sit amet risus euismod, at dictum justo imperdiet. Suspendisse id feugiat quam, quis mattis felis. Maecenas justo magna, pellentesque sed elementum sed, ultricies rutrum neque.",
@"Cras lobortis lacus arcu, non ullamcorper magna faucibus eu. Donec adipiscing eu odio ac dignissim.",
@"Vivamus sodales leo massa, in rhoncus purus placerat sit amet. Praesent mattis, lacus scelerisque porttitor interdum, urna sapien ullamcorper est, in placerat augue nulla eget turpis. Curabitur et feugiat orci, lacinia commodo nisl. Nulla sit amet tellus consequat, luctus tellus nec, porttitor libero. Proin mattis, purus nec pellentesque mollis, ligula sapien vehicula magna, et volutpat ligula ligula pulvinar risus. Cras hendrerit urna sagittis iaculis scelerisque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse ut porttitor arcu. Curabitur sit amet sodales tortor. Pellentesque consequat dui quis mi luctus consectetur. Etiam et dignissim felis.",
@"Pellentesque habitant",
@"Sed nec consectetur lectus. Mauris at enim nec purus sagittis pellentesque eget id urna."
];
// init table view
self.tableView = [[UITableView alloc] initWithFrame:self.view.frame];
self.tableView.separatorInset = UIEdgeInsetsZero;
self.tableView.dataSource = self;
self.tableView.delegate = self;
[self.view addSubview:self.tableView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)prefersStatusBarHidden
{
return YES;
}
#pragma mark - UITableViewDelegate Methods -
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.arrText.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = @"cellID";
DemoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if(cell == nil)
{
cell = [[DemoTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell = [self setupCell:cell forIndexPath:indexPath];
return cell;
}
// ---------------------------------------------------------------------------
// This method will setup the cell text and such
// ---------------------------------------------------------------------------
-(DemoTableViewCell *)setupCell:(DemoTableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath
{
cell.lblText.text = [self.arrText objectAtIndex:indexPath.row];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(offscreenCell == nil)
{
offscreenCell = [[DemoTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"offscreenCell"];
}
DemoTableViewCell *cell = [self setupCell:offscreenCell forIndexPath:indexPath];
[cell layoutIfNeeded];
return [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
}
@end
#import <UIKit/UIKit.h>
@interface DemoTableViewCell : UITableViewCell
@property (nonatomic, strong) UILabel *lblText;
@end
#import "DemoTableViewCell.h"
@implementation DemoTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
[self initView];
[self addAllConstraints];
}
return self;
}
- (void)awakeFromNib
{
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(void)initView
{
self.lblText = [[UILabel alloc] init];
self.lblText.numberOfLines = 0;
self.lblText.lineBreakMode = NSLineBreakByWordWrapping;
self.lblText.preferredMaxLayoutWidth = self.bounds.size.width - 40.0;
self.lblText.font = [UIFont systemFontOfSize:12];
[self.contentView addSubview:self.lblText];
}
-(void)addAllConstraints
{
self.lblText.translatesAutoresizingMaskIntoConstraints = NO;
id views = @{@"lblText": self.lblText};
// ------------------------------------------------------------
// Pin the label text subview to all four contentView edges.
//
// The lblText should automatically expand to fit the content
// text, no need for fixed height constraints here.
// ------------------------------------------------------------
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[lblText]-20-|" options:0 metrics:nil views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[lblText]-20-|" options:0 metrics:nil views:views]];
}
@end
Upvotes: 2