我正在尝试为我的表格视图中的一个单元格调整单元格高度。我正在根据相关单元格的“尺寸检查器”内的“行高”设置调整尺寸。当我在我的 iPhone 上运行应用程序时,单元格的默认大小是从表格视图中的“行大小”设置的。
如果我更改表格视图的“行大小”,那么所有单元格的大小都会更改。我不想这样做,因为我只想要一个单元格的自定义大小。我看过很多帖子都有解决问题的方案,但如果可能的话,我更愿意通过情节提要来解决。
在动态 单元格上,在 UITableView 上设置的 rowHeight
始终覆盖各个单元格的 rowHeight。
但是在 static 单元格上,在单个单元格上设置的 rowHeight
可以覆盖 UITableView。
不确定这是否是一个错误,Apple 可能是故意这样做的?
如果你使用 UITableViewController,实现这个方法:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
在一行的功能中,您可以选择高度。例如,
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) {
return 100;
}
else {
return 60;
}
}
在本例中,第一行高度为 100 像素,其余为 60 像素。
我希望这个可以帮助你。
对于动态单元格,在 UITableView
上设置的 rowHeight
始终覆盖各个单元格的 rowHeight
。
这种行为是,IMO,一个错误。任何时候你必须在两个地方管理你的 UI 都容易出错。例如,如果您在情节提要中更改单元格大小,则必须记住也要在 heightForRowAtIndexPath:
中更改它们。在 Apple 修复该错误之前,当前最好的解决方法是覆盖 heightForRowAtIndexPath:
,但使用情节提要中的实际原型单元来确定高度,而不是使用 magic numbers。这是一个例子:
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
/* In this example, there is a different cell for
the top, middle and bottom rows of the tableView.
Each type of cell has a different height.
self.model contains the data for the tableview
*/
static NSString *CellIdentifier;
if (indexPath.row == 0)
CellIdentifier = @"CellTop";
else if (indexPath.row + 1 == [self.model count] )
CellIdentifier = @"CellBottom";
else
CellIdentifier = @"CellMiddle";
UITableViewCell *cell =
[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
return cell.bounds.size.height;
}
这将确保在运行时自动获取对原型单元高度的任何更改,并且您只需要在一个地方管理您的 UI:故事板。
我已经构建了各种答案/评论提示的代码,以便这适用于使用原型单元的情节提要。
这段代码:
不需要将单元格高度设置在故事板中明显位置以外的任何位置
出于性能原因缓存高度
使用通用函数获取索引路径的单元格标识符以避免重复逻辑
感谢 Answerbot、Brennan 和 lensovet。
- (NSString *)cellIdentifierForIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = nil;
switch (indexPath.section)
{
case 0:
cellIdentifier = @"ArtworkCell";
break;
<... and so on ...>
}
return cellIdentifier;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
static NSMutableDictionary *heightCache;
if (!heightCache)
heightCache = [[NSMutableDictionary alloc] init];
NSNumber *cachedHeight = heightCache[cellIdentifier];
if (cachedHeight)
return cachedHeight.floatValue;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
CGFloat height = cell.bounds.size.height;
heightCache[cellIdentifier] = @(height);
return height;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
<... configure cell as usual...>
实际上有两个地方需要更改为行高,首先是单元格(您已经更改了它),现在选择表格视图并检查大小检查器
我认为这是一个错误。
尝试不通过实用程序检查器调整高度,而是通过鼠标直接在情节提要上拖动来调整高度。
我用这种方法解决了这个问题。
如果您使用的是 swift ,请像这样使用。不要使用情节提要选择行高。像这样以编程方式设置表格行高,
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 || indexPath.row == 1{
let cell = self.tableView.dequeueReusableCellWithIdentifier("section1", forIndexPath: indexPath) as! Section1TableViewCell
self.tableView.rowHeight = 150
cell.label1.text = "hiiiiii"
cell.label2.text = "Huiiilllllll"
return cell
} else {
let cell = self.tableView.dequeueReusableCellWithIdentifier("section2", forIndexPath: indexPath) as! Section2TableViewCell
self.tableView.rowHeight = 60
cell.label3.text = "llll"
return cell
}
}
cell.sizeToFit(); self.tableView.rowHeight = cell.frame.height
您可以借助以下几行从情节提要中获取 UITableviewCell 的高度(在 UITableviewController - 静态单元格中)。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];
return height;
}
在 XML 视图中打开情节提要并尝试编辑所需元素的 rowHeight
属性。
当我尝试为我的原型行设置自定义 rowHeight 时,它对我有用。它不是通过检查器工作的,而是通过 XML 工作的。
您可以将原型 cells
与自定义 height
一起使用,然后调用 cellForRowAtIndexPath:
并返回其 frame.height
。:。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self tableView:tableView
cellForRowAtIndexPath:indexPath];
return cell.frame.size.height;
}
如果要设置静态行高,可以执行以下操作:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 120;
}
我最近一直在为此苦苦挣扎。我的问题是上面使用 heightForRowAtIndexPath:
方法发布的解决方案适用于模拟器中的 iOS 7.1,但随后通过简单地切换到 iOS 8.1 就完全搞砸了结果。
我开始阅读有关自调整单元格的更多信息(在 iOS 8 中引入,read here)。很明显,在 iOS 8 中使用 UITableViewAutomaticDimension
会有所帮助。我尝试使用该技术并删除了 heightForRowAtIndexPath:
的使用,瞧,它现在在 iOS 8 中运行良好。但后来 iOS 7 不是。我该怎么办?我需要 heightForRowAtIndexPath:
用于 iOS 7 而不是 iOS 8。
这是我的解决方案(为简洁起见进行了整理),它借鉴了上面发布的@JosephH 的答案:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = 50.;
self.tableView.rowHeight = UITableViewAutomaticDimension;
// ...
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
return UITableViewAutomaticDimension;
} else {
NSString *cellIdentifier = [self reuseIdentifierForCellAtIndexPath:indexPath];
static NSMutableDictionary *heightCache;
if (!heightCache)
heightCache = [[NSMutableDictionary alloc] init];
NSNumber *cachedHeight = heightCache[cellIdentifier];
if (cachedHeight)
return cachedHeight.floatValue;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
CGFloat height = cell.bounds.size.height;
heightCache[cellIdentifier] = @(height);
return height;
}
}
- (NSString *)reuseIdentifierForCellAtIndexPath:(NSIndexPath *)indexPath {
NSString * reuseIdentifier;
switch (indexPath.row) {
case 0:
reuseIdentifier = EventTitleCellIdentifier;
break;
case 2:
reuseIdentifier = EventDateTimeCellIdentifier;
break;
case 4:
reuseIdentifier = EventContactsCellIdentifier;
break;
case 6:
reuseIdentifier = EventLocationCellIdentifier;
break;
case 8:
reuseIdentifier = NotesCellIdentifier;
break;
default:
reuseIdentifier = SeparatorCellIdentifier;
break;
}
return reuseIdentifier;
}
SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0") 实际上来自我正在使用的一组宏定义,我在某处找到了这些定义(非常有帮助)。它们被定义为:
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
使用 Swift 4 处理 XCode 9 时也出现了同样的问题。
为 Cell 内的 UI 元素添加 AutoLayout,自定义单元格行高将按照指定相应地工作。
对于动态单元格,在 UITableView 上设置的 rowHeight 始终会覆盖单个单元格的 rowHeight。如果行内的内容,只需计算动态高度。
我能找到的唯一真正的解决方案是这个
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = ...; // Instantiate with a "common" method you'll use again in cellForRowAtIndexPath:
return cell.frame.size.height;
}
这有效并且允许没有可怕的开关/如果复制故事板中已经存在的逻辑。不确定性能,但我猜当到达 cellForRow:
时,单元格已经被初始化,它的速度也一样快。当然,这里可能有附带损害,但它看起来对我来说很好用。
我也在这里发布了这个:https://devforums.apple.com/message/772464
编辑:Ortwin Gentz 提醒我,将为 TableView 的 所有 单元格调用 heightForRowAtIndexPath:
,而不仅仅是可见的单元格。听起来合乎逻辑,因为 iOS 需要知道总高度才能显示正确的滚动条。这意味着它在小型 TableView(如 20 个单元格)上可能没问题,但在 1000 个单元格的 TableView 上忘记它。
此外,之前使用 XML 的技巧:与我的第一条评论相同。正确的值已经存在。
添加为评论,但发布为可见性的答案:
如果您最初将表格视图设置为“静态单元格”,然后将其更改为“动态原型”,这似乎也存在问题。我遇到了一个问题,甚至 heightForRowAtIndexPath
的委托方法都被忽略了。我首先通过直接编辑情节提要 XML 来解决它,然后最后只是从头开始重建情节提要场景,从一开始就使用动态原型。
鉴于我没有通过 Interface Builder 找到该问题的任何解决方案,我决定使用两个动态单元格在 Swift 中发布该问题的编程解决方案,即使最初的问题要求通过 Interface Builder 提供解决方案。无论如何,我认为这可能对 Stack Overflow 社区有所帮助:
import UIKit
enum SignInUpMenuTableViewControllerCellIdentifier: String {
case BigButtonCell = "BigButtonCell"
case LabelCell = "LabelCell"
}
class SignInUpMenuTableViewController: UITableViewController {
let heightCache = [SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell : CGFloat(50),
SignInUpMenuTableViewControllerCellIdentifier.LabelCell : CGFloat(115)]
private func cellIdentifierForIndexPath(indexPath: NSIndexPath) -> SignInUpMenuTableViewControllerCellIdentifier {
if indexPath.row == 2 {
return SignInUpMenuTableViewControllerCellIdentifier.LabelCell
} else {
return SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell
}
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return self.heightCache[self.cellIdentifierForIndexPath(indexPath)]!
}
...
}
您可以做的另一件事是转到您的文档大纲,选择您的原型单元格嵌套的表格视图。然后在 Size Inspector 上,将 table view 的 Row Height 更改为所需的值并取消选中 Automatic 框。
UITableView
内容从Dynamic Prototypes
更改为Static Cells
,我这样做了,我的整个项目爆炸了.. 我自己差点被杀。