这篇博客主要在于,解释如何通过仅仅使用Autolayout很很少的代码,显示高度不同的Cell。虽然标题说的是TableView,但是CollectionView同样适合。但是,这种方法只使用iOS7和iOS8。

在Github上的实例代码是DynamicTableViewCellHeight

这个Demo显示了一些名人名言,他看起来像这样:

preferredMaxLayoutWidth

这种方法,主要来自于preferredMaxLayoutWidth属性。对于更多高级用法,请看Auto Layout and Views that Wrap

User Interface

我使用的是Storyboard, 但是你能够使用xib或者代码, 对于如何使用代码,你可以看一下这篇文章AutoSize UITableViewCell height programmatically

这里,“引言Label”显示多行(通过设置numberOfLines属性为0)。因为我们有2个Label,AutoLayout不知道如何扩大,不知道cell的大小改变时哪一个Label保持大小不变。在这种情况下,我想要“引言Label”扩大,所以减少减少垂直方向Hugging优先级,并且增加保持自身大小不变优先级。

关于hugging和resistance优先级的区别,可以看这篇文章Cocoa Autolayout: content hugging vs content compression resistance priority

注意:

1、Dynamic Table View Cell Height and Auto Layout,这篇博客告诉我们,我们应该给labels的“intrinsic content”属性到1000,并且设置Intrinsic Size为占位符大小。我认为这是不需要的。

2、你必须给TableViewCell的contentView设置属性。

3、对于在Interface Builder中的CollectionViewCell。你不会看到contentView,但是你真的是和contentView打交道。

Cell

QuoteTableViewCell.h

 @interface QuoteTableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UILabel *numberLabel;
@property (weak, nonatomic) IBOutlet UILabel *quoteLabel; @end

QuoteTableViewCell.m

 @implementation QuoteTableViewCell

 // (1)
- (void)setBounds:(CGRect)bounds
{
[super setBounds:bounds]; self.contentView.frame = self.bounds;
} - (void)layoutSubviews
{
[super layoutSubviews]; // (2)
[self.contentView updateConstraintsIfNeeded];
[self.contentView layoutIfNeeded]; // (3)
self.quoteLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.quoteLabel.frame);
} @end

ViewController

ViewController.m

 #define SYSTEM_VERSION                              ([[UIDevice currentDevice] systemVersion])
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([SYSTEM_VERSION compare:v options:NSNumericSearch] != NSOrderedAscending)
#define IS_IOS8_OR_ABOVE (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) @interface ViewController () <UITableViewDataSource, UITableViewDelegate> @property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSArray *items;
@property (nonatomic, strong) QuoteTableViewCell *prototypeCell; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad]; [self setupTableView];
[self loadData];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} #pragma mark - Setup
- (void)setupTableView
{
self.tableView.dataSource = self;
self.tableView.delegate = self;
} #pragma mark - Data
- (void)loadData
{
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"quotes" ofType:@"plist"];
self.items = [[NSArray alloc] initWithContentsOfFile:plistPath]; [self.tableView reloadData];
} #pragma mark - PrototypeCell
// (4)
- (QuoteTableViewCell *)prototypeCell
{
if (!_prototypeCell) {
_prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([QuoteTableViewCell class])];
} return _prototypeCell;
} #pragma mark - Configure
- (void)configureCell:(QuoteTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *quote = self.items[indexPath.row]; cell.numberLabel.text = [NSString stringWithFormat:@"Quote %ld", (long)indexPath.row];
cell.quoteLabel.text = quote;
} #pragma mark - UITableViewDataSouce
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return ;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.items.count;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
QuoteTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([QuoteTableViewCell class])]; [self configureCell:cell forRowAtIndexPath:indexPath]; return cell;
} #pragma mark - UITableViewDelegate
// (5)
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
} - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// (6)
if (IS_IOS8_OR_ABOVE) {
return UITableViewAutomaticDimension;
} // (7)
//self.prototypeCell.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), CGRectGetHeight(self.prototypeCell.bounds)); [self configureCell:self.prototypeCell forRowAtIndexPath:indexPath]; // (8)
[self.prototypeCell updateConstraintsIfNeeded];
[self.prototypeCell layoutIfNeeded]; // (9)
return [self.prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; } @end

注意以下几点:

1、Auto Layout in UICollectionViewCell not working

2、AutoSize UITableViewCell height programmatically

Make sure the contentView does a layout pass here so that its subviews have their frames set, which we need to use to set the preferredMaxLayoutWidth below.

Set the preferredMaxLayoutWidth of the mutli-line bodyLabel based on the evaluated width of the label’s frame, as this will allow the text to wrap correctly, and as a result allow the label to take on the correct height.

3、你只需要调用[self.contentView layoutIfNeeded]。

4、如果你要改变某些限制,你需要调用[self.contentView updateConstraintsIfNeeded]。

5、如果你调用[self.contentView updateConstraintsIfNeeded],你必须在之前调用[self.contentView layoutIfNeeded]。

6、不需要调用[self.contentView setsNeedLayout],或者self.contentView setsNeedUpdateConstraints]。

ViewController

 #define SYSTEM_VERSION                              ([[UIDevice currentDevice] systemVersion])
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([SYSTEM_VERSION compare:v options:NSNumericSearch] != NSOrderedAscending)
#define IS_IOS8_OR_ABOVE (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) @interface ViewController () <UITableViewDataSource, UITableViewDelegate> @property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSArray *items;
@property (nonatomic, strong) QuoteTableViewCell *prototypeCell; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad]; [self setupTableView];
[self loadData];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} #pragma mark - Setup
- (void)setupTableView
{
self.tableView.dataSource = self;
self.tableView.delegate = self;
} #pragma mark - Data
- (void)loadData
{
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"quotes" ofType:@"plist"];
self.items = [[NSArray alloc] initWithContentsOfFile:plistPath]; [self.tableView reloadData];
} #pragma mark - PrototypeCell
// (4)
- (QuoteTableViewCell *)prototypeCell
{
if (!_prototypeCell) {
_prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([QuoteTableViewCell class])];
} return _prototypeCell;
} #pragma mark - Configure
- (void)configureCell:(QuoteTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *quote = self.items[indexPath.row]; cell.numberLabel.text = [NSString stringWithFormat:@"Quote %ld", (long)indexPath.row];
cell.quoteLabel.text = quote;
} #pragma mark - UITableViewDataSouce
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return ;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.items.count;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
QuoteTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([QuoteTableViewCell class])]; [self configureCell:cell forRowAtIndexPath:indexPath]; return cell;
} #pragma mark - UITableViewDelegate
// (5)
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
} - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// (6)
if (IS_IOS8_OR_ABOVE) {
return UITableViewAutomaticDimension;
} // (7)
//self.prototypeCell.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), CGRectGetHeight(self.prototypeCell.bounds)); [self configureCell:self.prototypeCell forRowAtIndexPath:indexPath]; // (8)
[self.prototypeCell updateConstraintsIfNeeded];
[self.prototypeCell layoutIfNeeded]; // (9)
return [self.prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; } @end

7、原型cell绝不会显示出来,它用来布局一个cell并且决定一个需要的高度。

8、你能够使用UITableViewAutomaticDimension,或者使用一个大约合理的高度。

9、iOS8 autoSizing属性需要使用UITableViewAutomaticDimension。

Fantageek翻译系列之《使用Autolayout显示变化高度的UITableViewCell》的更多相关文章

  1. 《Entity Framework 6 Recipes》中文翻译系列 目录篇 -持续更新

    为了方便大家的阅读和学习,也是响应网友的建议,在这里为这个系列做一个目录.在目录开始这前,我先来回答之前遇到的几个问题. 1.为什么要学习EF? 这个问题很简单,项目需要.这不像学校,没人强迫你学习! ...

  2. 使用Material Design 创建App翻译系列----材料主题的使用(Using Material Theme)

    上一篇是使用Material Design 创建App翻译系列--開始学习篇,进入正题: 新的材料主题提供了下面内容: 1. 提供了同意设置颜色板的系统部件组件. 2. 为这些系统组件提供了触摸反馈动 ...

  3. ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第六章:管理产品图片——多对多关系(上篇)

    在这章中,我们将学习如何创建一个管理图片的新实体,如何使用HTML表单上传图片文件,并使用多对多关系将它们和产品关联起来,如何将图片存储在文件系统中.在这章中,我们还会学习更加复杂的异常处理,如何向模 ...

  4. 21.翻译系列:Entity Framework 6 Power Tools【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/entity-framework-power-tools.aspx 大家好,这里就是EF ...

  5. 《Entity Framework 6 Recipes》中文翻译 ---- 系列教程

    为了方便大家的阅读和学习,也是响应网友的建议,在这里为这个系列做一个目录.在目录开始这前,我先来回答之前遇到的几个问题. 1.为什么要学习EF? 这个问题很简单,项目需要.这不像学校,没人强迫你学习! ...

  6. 使用Material Design 创建App翻译系列---列表和卡片集的创建

    上一篇是使用Material Design 创建App翻译系列--材料主题的使用(Using Material Theme),进入正题: 想要在应用里创建Material Design风格的复杂列表和 ...

  7. 20.2.翻译系列:EF 6中基于代码的数据库迁移技术【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/code-based-migration-in-code-first.aspx EF 6 ...

  8. 20.1翻译系列:EF 6中自动数据迁移技术【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/automated-migration-in-code-first.aspx EF 6 ...

  9. 20.翻译系列:Code-First中的数据库迁移技术【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/migration-in-code-first.aspx EF 6 Code-First ...

随机推荐

  1. (转)C# DateTime格式化大全

    //c datetime 格式化 DateTime dt = DateTime.Now; Label1.Text = dt.ToString();//2005-11-5 13:21:25 Label2 ...

  2. @Html.Partial,@Html.Action,@Html.RenderPartial,@Html.RenderAction

    1.带有Render的方法返回值是void,在方法内部进行输出: 不带的返回值类型为MvcHtmlString,所以只能这样使用: @Html.Partial 对应 @{Html.RenderPart ...

  3. IDEA - Project files cannot be watched (are they under network mount?)

    在64位Linux系统上使用IDEA时遇到如下问题,启动时警告信息External file changes sync may be slow Project files cannot be watc ...

  4. 关于R文件丢失的一个问题

    android studio在编辑布局文件时,一般为了省事,如TextView控件中的text属性这样写 android:text="<500",编译不会报错,但是运行时会出 ...

  5. (原)windows8.1上使用opencv for python

    转载请注明出处: http://www.cnblogs.com/darkknightzh/p/6204100.html 参考网址: http://www.docs.opencv.org/master/ ...

  6. 分割gbk中文出现乱码的问题解决

    近日遇到一个神奇的字“弢(tao)”. 具体的过程是这样的: $list = explode('|', 'abc弢|bc'); var_dump($list); 取得这个分割的结果. 和想象不同,结果 ...

  7. 用PHP删除文件操作unlink

    使用unlink要注意的是$filename的值,要用的是本地绝对地址.比如"c:\aaa\a.jpg",不能用相对地址比如:"../aa.jpg",那么如果在 ...

  8. Openjudge 百练第4109题

    在OpenJudge看到一个题目(#4109),题目描述如下: 小明和小红去参加party.会场中总共有n个人,这些人中有的是朋友关系,有的则相互不认识.朋友关系是相互的,即如果A是B的朋友,那么B也 ...

  9. 二维指针*(void **)的研究(uC/OS-II案例) 《转载》

    uC/OS-II内存管理函数内最难理解的部分就是二维指针,本文以图文并茂的方式对二维指针进行了详细分析与讲解.看完本文,相信对C里面指针的概念又会有进一步的认识. 一.OSMemCreate( ) 函 ...

  10. bzoj 2075: [POI2004]KAG

    整天鬼畜题搞搞,感觉药丸…… 这种题出到xjoi模拟题里,太神了…… 这题的核心在于分割Cograph,尝试把Cograph的合成过程给求出来. 我们将这张图中的边为黑边,在这张图的补图中出现的边为白 ...