ios 基于内容的动态 UITableView 单元格高度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10287298/
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
Dynamic UITableView Cell Height Based on Contents
提问by Adam Waite
I have a UITableView
that is populated with custom cells (inherited from UITableViewCell
), each cell contains a UIWebView
that is automatically resize based on it's contents. Here's the thing, how can I change the height of the UITableView
cells based on their content (variable webView
).
我有一个UITableView
填充了自定义单元格(继承自UITableViewCell
)的单元格,每个单元格都包含一个UIWebView
根据其内容自动调整大小的单元格。事情就是这样,如何根据UITableView
单元格的内容(变量webView
)更改单元格的高度。
The solution must be dynamic since the HTML used to populate the UIWebViews
is parsed from an ever changing feed.
解决方案必须是动态的,因为用于填充 的 HTMLUIWebViews
是从不断变化的提要中解析出来的。
I have a feeling I need to use the UITableView
delegate method heightForRowAtIndexPath
but from it's definition:
我有一种感觉我需要使用UITableView
委托方法,heightForRowAtIndexPath
但从它的定义来看:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
;//This needs to be variable
}
I can't access the cell or it's contents. Can I change the height of the cell in cellForRowAtIndexPath
?
我无法访问单元格或其内容。我可以更改单元格的高度cellForRowAtIndexPath
吗?
Any help would be grand. Thanks.
任何帮助都会很棒。谢谢。
Note
笔记
I asked this question over 2 years ago. With the intro of auto layout the best solution for iOS7 can be found:
2年前我问过这个问题。随着自动布局的介绍,可以找到适用于 iOS7 的最佳解决方案:
Using Auto Layout in UITableView for dynamic cell layouts & variable row heights
在 UITableView 中使用自动布局进行动态单元格布局和可变行高
and on iOS8 this functionality is built in the SDK
在 iOS8 上,此功能内置在 SDK 中
采纳答案by Nyth
The best way that I've found for dynamic height is to calculate the height beforehand and store it in a collection of some sort (probably an array.) Assuming the cell contains mostly text, you can use -[NSString sizeWithFont:constrainedToSize:lineBreakMode:]
to calculate the height, and then return the corresponding value in heightForRowAtIndexPath:
我发现的动态高度的最佳方法是预先计算高度并将其存储在某种集合(可能是数组)中。假设单元格主要包含文本,您可以使用它-[NSString sizeWithFont:constrainedToSize:lineBreakMode:]
来计算高度,然后返回对应的值heightForRowAtIndexPath:
If the content is constantly changing, you could implement a method that updated the array of heights when new data was provided.
如果内容不断变化,您可以实现一种在提供新数据时更新高度数组的方法。
回答by Santa Claus
This usually works pretty well:
这通常效果很好:
Objective-C:
目标-C:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
Swift:
迅速:
override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
return UITableViewAutomaticDimension;
}
回答by Nyth
self.tblVIew.estimatedRowHeight = 500.0; // put max you expect here.
self.tblVIew.rowHeight = UITableViewAutomaticDimension;
回答by Alexandre
I tried many solutions, but the one that worked was this, suggested by a friend:
我尝试了很多解决方案,但最有效的是一个朋友建议的解决方案:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
int height = [StringUtils findHeightForText:yourLabel havingWidth:yourWidth andFont:[UIFont systemFontOfSize:17.0f]];
height += [StringUtils findHeightForText:yourOtherLabel havingWidth:yourWidth andFont:[UIFont systemFontOfSize:14.0f]];
return height + CELL_SIZE_WITHOUT_LABELS; //important to know the size of your custom cell without the height of the variable labels
}
The StringUtils.h class:
StringUtils.h 类:
#import <Foundation/Foundation.h>
@interface StringUtils : NSObject
+ (CGFloat)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font;
@end
StringUtils.m class:
StringUtils.m 类:
#import "StringUtils.h"
@implementation StringUtils
+ (CGFloat)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font {
CGFloat result = font.pointSize+4;
if (text) {
CGSize size;
CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:font}
context:nil];
size = CGSizeMake(frame.size.width, frame.size.height+1);
result = MAX(size.height, result); //At least one row
}
return result;
}
@end
It worked perfectly for me. I had a Custom Cell with 3 images with fixed sizes, 2 labels with fixed sizes and 2 variable labels.
它非常适合我。我有一个自定义单元格,其中包含 3 个固定大小的图像、2 个固定大小的标签和 2 个可变标签。
回答by Daniel Saidi
The big problem with cells with dynamic height in iOS is that the table vc must calculate and return a height of each cell before the cells are drawn. Before a cell is drawn, though, it doesn't have a frame and thus no width. This causes a problem if your cell is to change its height based on, say, the amount of text in the textLabel, since you do not know its width.
iOS 中具有动态高度的单元格的一个大问题是表格 vc 必须在绘制单元格之前计算并返回每个单元格的高度。但是,在绘制单元格之前,它没有框架,因此没有宽度。如果您的单元格要根据 textLabel 中的文本量更改其高度,则会导致问题,因为您不知道它的宽度。
A common solution that I've seen is that people define a numeric value for the cell width. This is a bad approach, since tables can be plain or grouped, use iOS 7 or iOS 6 styling, be displayed on an iPhone or iPad, in landscape or portrait mode etc.
我见过的一个常见解决方案是人们为单元格宽度定义一个数值。这是一个糟糕的方法,因为表格可以是普通的或分组的,使用 iOS 7 或 iOS 6 样式,在 iPhone 或 iPad 上显示,以横向或纵向模式等。
I struggled with these issues in an iOS app of mine, which supports iOS5+ and both iPhone and iPad with multiple orientations. I needed a convenient way to automate this and leave the logic out of the view controller. The result became a UITableViewController sub class (so that it can hold state) that supports default cells (Default and Subtitle style) as well as custom cells.
我在我的一个 iOS 应用程序中遇到了这些问题,该应用程序支持 iOS5+ 以及具有多个方向的 iPhone 和 iPad。我需要一种方便的方法来自动执行此操作并将逻辑排除在视图控制器之外。结果变成了一个支持默认单元格(默认和字幕样式)以及自定义单元格的 UITableViewController 子类(以便它可以保持状态)。
You can grab it at GitHub (https://github.com/danielsaidi/AutoSizeTableView). I hope it helps those of you who still struggle with this problem. If you do check it out, I'd love to hear what you think and if it worked out for you.
您可以在 GitHub ( https://github.com/danielsaidi/AutoSizeTableView)上获取它。我希望它可以帮助那些仍在努力解决这个问题的人。如果您确实检查了它,我很想听听您的想法以及它是否适合您。
回答by Joseph DeCarlo
Here is code that I used for dynamic cell height when fetching tweets from twitter and then storing them in CoreData for offline reading.
这是我在从 twitter 获取推文然后将它们存储在 CoreData 中以供离线阅读时用于动态单元格高度的代码。
Not only does this show how to get the cell and data content, but also how to dynamically size a UILabel to the content with padding
这不仅展示了如何获取单元格和数据内容,还展示了如何使用 padding 根据内容动态调整 UILabel 的大小
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
Tweet *tweet = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString* text = tweet.Text;
TweetTableViewCell *cell = (TweetTableViewCell*)[self tableView:tableView cellForRowAtIndexPath:indexPath];
//Set the maximum size
CGSize maximumLabelSize = cell.tweetLabel.frame.size;
CGPoint originalLocation = cell.tweetLabel.frame.origin;
//Calculate the new size based on the text
CGSize expectedLabelSize = [text sizeWithFont:cell.tweetLabel.font constrainedToSize:maximumLabelSize lineBreakMode:cell.tweetLabel.lineBreakMode];
//Dynamically figure out the padding for the cell
CGFloat topPadding = cell.tweetLabel.frame.origin.y - cell.frame.origin.y;
CGFloat bottomOfLabel = cell.tweetLabel.frame.origin.y + cell.tweetLabel.frame.size.height;
CGFloat bottomPadding = cell.frame.size.height - bottomOfLabel;
CGFloat padding = topPadding + bottomPadding;
CGFloat topPaddingForImage = cell.profileImage.frame.origin.y - cell.frame.origin.y;
CGFloat minimumHeight = cell.profileImage.frame.size.height + topPaddingForImage + bottomPadding;
//adjust to the new size
cell.tweetLabel.frame = CGRectMake(originalLocation.x, originalLocation.y, cell.tweetLabel.frame.size.width, expectedLabelSize.height);
CGFloat cellHeight = expectedLabelSize.height + padding;
if (cellHeight < minimumHeight) {
cellHeight = minimumHeight;
}
return cellHeight;
}
回答by alex
Also i think such an algorithm will suit you:
我也认为这样的算法适合你:
1) in cellForrowAtIndexPath you activate your webviews for loading and give them tags equal to indexPath.row
1) 在 cellForrowAtIndexPath 中激活您的 webviews 以进行加载并为它们提供等于 indexPath.row 的标签
2) in webViewDidFinishLoading you calculate the height of the content in the cell, and compose a dictionary with keys and values like this: key= indexPath.row value = height
2) 在 webViewDidFinishLoading 中计算单元格中内容的高度,并用这样的键和值组成一个字典:key= indexPath.row value = height
3)call [tableview reloadData]
3)调用[tableview reloadData]
4) in [tableview cellForRowAtIndexPath:indexPath] set proper heights for corresponding cells
4) 在 [tableview cellForRowAtIndexPath:indexPath] 中为相应的单元格设置适当的高度
回答by iOS
This is one of my nice solution. it's worked for me.
这是我很好的解决方案之一。它对我有用。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cell.textLabel.text = [_nameArray objectAtIndex:indexPath.row];
cell.textLabel.numberOfLines = 0;
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
We need to apply these 2 changes.
我们需要应用这两个更改。
1)cell.textLabel.numberOfLines = 0;
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
2)return UITableViewAutomaticDimension;
回答by Diego Carrera
In Swift 4+ you can set it dinamic
在 Swift 4+ 中,您可以将其设置为动态
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
回答by Diego Carrera
Swift Use custom cell and labels. Set up the constrains for the UILabel. (top, left, bottom, right) Set lines of the UILabel to 0
Swift 使用自定义单元格和标签。为 UILabel 设置约束。(上、左、下、右)将 UILabel 的行设置为 0
Add the following code in the viewDidLoad method of the ViewController:
在 ViewController 的 viewDidLoad 方法中添加如下代码:
tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableViewAutomaticDimension
// Delegate & data source
// 委托和数据源
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension;
}