xcode 如何使用动态单元格高度和自动布局以编程方式创建一个非常基本的 UITableView?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26354618/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create a very basic UITableView programmatically with dynamic cell height and auto layout?
提问by Avnish Gaur
Please note: I know there are quite a few examples on similar lines. I am looking for the most basic solution with the minimum setup required.
请注意:我知道有很多类似的例子。我正在寻找需要最少设置的最基本的解决方案。
I was trying to create one on my own, and I know I am way off..
我试图自己创建一个,但我知道我离得很远。
#import "ViewController.h"
@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@property(strong, nonatomic) UITableView *tableView;
@property(strong, nonatomic) NSMutableArray *dataArray;
@property (strong, nonatomic) UITableViewCell *customCell;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStylePlain];
[self.tableView setDataSource:self];
[self.tableView setDelegate:self];
[self.tableView setShowsVerticalScrollIndicator:NO];
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
self.tableView.rowHeight = UITableViewAutomaticDimension;
[self.view addSubview:self.tableView];
self.dataArray = [@[@"For the past 33 years, I have looked in the mirror every morning and asked myself: 'If today were the last day of my life, would I want to do what I am about to do today?' And whenever the answer has been 'No' for too many days in a row, I know I need to change something. -Steve Jobs",
@"Be a yardstick of quality. Some people aren't used to an environment where excellence is expected. - Steve Jobs",
@"Innovation distinguishes between a leader and a follower. -Steve Jobs"] mutableCopy];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.dataArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier = @"CustomCell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.backgroundColor = [UIColor colorWithRed:249.0/255 green:237.0/255 blue:224.0/255 alpha:1.0];
int dataIndex = (int) indexPath.row % [self.dataArray count];
cell.textLabel.text = self.dataArray[dataIndex];
cell.textLabel.numberOfLines = 0;
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
NSDictionary *views = @{@"label":cell.textLabel};
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|"
options:0
metrics:nil
views:views];
[cell.contentView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]|"
options: 0
metrics:nil
views:views];
[cell.contentView addConstraints:constraints];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Calculate a height based on a cell
if(!self.customCell) {
self.customCell = [self.tableView dequeueReusableCellWithIdentifier:@"CustomCell"];
}
// Configure the cell
int dataIndex = (int) indexPath.row % [self.dataArray count];
self.customCell.textLabel.text = self.dataArray[dataIndex];
// auto layout
NSDictionary *views = @{@"label":self.customCell.textLabel};
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|"
options:0
metrics:nil
views:views];
[self.customCell.contentView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]|"
options: 0
metrics:nil
views:views];
[self.customCell.contentView addConstraints:constraints];
// Layout the cell
[self.customCell layoutIfNeeded];
// Get the height for the cell
CGFloat height = [self.customCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
// Padding of 1 point (cell separator)
CGFloat separatorHeight = 1;
return height + separatorHeight;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 140;
}
@end
采纳答案by Avnish Gaur
So after going through a lot of examples, I finally understood what was wrong. Its one of those things where one missing lines messes up the whole code. For me it was,
所以在经历了很多例子之后,我终于明白了什么是错的。这是其中一个缺失的行弄乱了整个代码的事情之一。对我来说是,
cell.bodyLabel.preferredMaxLayoutWidth = tableView.bounds.size.width;
which we need to add at heightForRowAtIndexPath method or it gives constraints error.
我们需要在 heightForRowAtIndexPath 方法中添加它,否则它会给出约束错误。
I got to the solution thanks to one of the comments to the amazing answer here. Although in the sample code given in the answer there, the line of code above is in function cellForRowAtIndexPath instead of heightForRowAtIndexPath. But my code couldn't run that way.
由于对此处惊人答案的评论之一,我找到了解决方案。尽管在那里的答案中给出的示例代码中,上面的代码行在函数 cellForRowAtIndexPath 而不是 heightForRowAtIndexPath 中。但是我的代码不能那样运行。
So, the basic code is,
所以,基本代码是,
// RJCell.h
// RJCell.h
#import <UIKit/UIKit.h>
@interface RJTableViewCell : UITableViewCell
@property (strong, nonatomic) UILabel *titleLabel;
@property (strong, nonatomic) UILabel *bodyLabel;
@end
// RJCell.m
// RJCell.m
#import "RJTableViewCell.h"
@interface RJTableViewCell ()
@property (nonatomic, assign) BOOL didSetupConstraints;
@end
@implementation RJTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.titleLabel = [[UILabel alloc] init];
[self.titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.titleLabel setLineBreakMode:NSLineBreakByTruncatingTail];
[self.titleLabel setNumberOfLines:1];
[self.titleLabel setTextAlignment:NSTextAlignmentLeft];
[self.titleLabel setTextColor:[UIColor blackColor]];
[self.titleLabel setBackgroundColor:[UIColor clearColor]];
[self.contentView addSubview:self.titleLabel];
// Add this label to the button
self.bodyLabel = [[UILabel alloc] init];
[self.bodyLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.bodyLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.bodyLabel setLineBreakMode:NSLineBreakByTruncatingTail];
[self.bodyLabel setNumberOfLines:0];
[self.bodyLabel setTextAlignment:NSTextAlignmentLeft];
[self.bodyLabel setTextColor:[UIColor darkGrayColor]];
[self.bodyLabel setBackgroundColor:[UIColor clearColor]];
[self.contentView addSubview:self.bodyLabel];
}
return self;
}
- (void)updateConstraints {
[super updateConstraints];
if (self.didSetupConstraints) return;
// Get the views dictionary
NSDictionary *viewsDictionary =
@{
@"titleLabel" : self.titleLabel,
@"bodyLabel" : self.bodyLabel
};
NSString *format;
NSArray *constraintsArray;
//Create the constraints using the visual language format
format = @"V:|-10-[titleLabel]-10-[bodyLabel]-10-|";
constraintsArray = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:viewsDictionary];
[self.contentView addConstraints:constraintsArray];
format = @"|-10-[titleLabel]-10-|";
constraintsArray = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:viewsDictionary];
[self.contentView addConstraints:constraintsArray];
format = @"|-10-[bodyLabel]-10-|";
constraintsArray = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:viewsDictionary];
[self.contentView addConstraints:constraintsArray];
self.didSetupConstraints = YES;
}
@end
// RJTableViewController.h
// RJTableViewController.h
#import <UIKit/UIKit.h>
@interface RJTableViewController : UITableViewController
@end
// RJTableViewController.m
// RJTableViewController.m
#import "RJTableViewController.h"
#import "RJTableViewCell.h"
static NSString *CellIdentifier = @"CellIdentifier";
@interface RJTableViewController ()
@property(strong,nonatomic) NSMutableArray *titleArray;
@property(strong,nonatomic) NSMutableArray *bodyArray;
@end
@implementation RJTableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
self.title = @"Table View Controller";
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[RJTableViewCell class] forCellReuseIdentifier:CellIdentifier];
self.titleArray = [[UIFont familyNames] mutableCopy];
for(int i = 0; i < 100; i++) {
[self.titleArray addObjectsFromArray:[UIFont familyNames]];
}
self.bodyArray = [@[@"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",@"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",@"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",@"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."] mutableCopy];
}
- (void)contentSizeCategoryChanged:(NSNotification *)notification
{
[self.tableView reloadData];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.titleArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
RJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
int dataIndex = (int) indexPath.row % [self.bodyArray count];
cell.titleLabel.text = self.titleArray[indexPath.row];
cell.bodyLabel.text = self.bodyArray[dataIndex];
// Make sure the constraints have been added to this cell, since it may have just been created from scratch
[cell setNeedsUpdateConstraints];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
RJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
int dataIndex = (int) indexPath.row % [self.bodyArray count];
cell.titleLabel.text = self.titleArray[indexPath.row];
cell.bodyLabel.text = self.bodyArray[dataIndex];
cell.bodyLabel.preferredMaxLayoutWidth = tableView.bounds.size.width - (20.0 * 2.0f);
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 200.0f;
}
@end
Basically, the tricky part is at two places, first setting up the constraints. Second, implementing the methods heightForRowAtIndexPath and cellForRowAtIndexPath.
基本上,棘手的部分在两个地方,首先是设置约束。其次,实现方法 heightForRowAtIndexPath 和 cellForRowAtIndexPath。