情节提要中的“自定义单元格行高”设置没有响应


213

我正在尝试为表格视图中的一个单元格调整单元格高度。我正在从相关单元格的“大小检查器”内的“行高”设置中调整大小。当我在iPhone上运行该应用程序时,该单元格具有表格视图中“行大小”中设置的默认大小。

如果更改表视图的“行大小”,则所有单元格的大小都会更改。我不想这样做,因为我只想要一个单元的自定义大小。我看到很多帖子都提供了针对该问题的程序化解决方案,但如果可能的话,我宁愿通过情节提要进行操作。

Answers:


295

动态单元格上,rowHeight在UITableView上设置的值始终会覆盖单个单元格的rowHeight。

但是在静态单元格上,rowHeight在单个单元格上设置可以覆盖UITableView的。

不确定是否是bug,Apple可能有意这样做吗?


36
正确答案3,尤其是因为此答案适用于Interface Builder / Storyboards。如果在IB中选择单元格,则“ 大小”检查器在顶部显示“行高”(带有“自定义”复选框),但是,如果您选择整个表格视图,则“ 大小”检查器也在顶部显示“行高”(无“自定义” “ 在这种情况下)。如pixelfreak所说,仅表格视图设置用于动态单元格。(不确定是否是故意的)
大黄

8
这个答案意味着解决方案只是将UITableView内容从更改Dynamic PrototypesStatic Cells,我这样做了,我的整个项目都炸毁了..差点就自杀了。
2013年

4
有什么办法可以找回这个号码?深入研究的唯一方法是跳入情节提要并将其从情节提要中拉出来吗?
Biclops,2013年

这绝对不是错误,因为您的表是动态的,那么系统如何知道使用这些单元格的地方呢?以及每个原型将使用多少次。
文森特·伯尼尔

如果最初将表视图设置为“静态单元格”,然后将其更改为“动态原型”,那么似乎也存在问题。我有一个问题,即使是rowHeight的委托方法也被忽略了。我首先通过直接编辑情节提要XML来解决该问题,然后才从头开始使用动态原型从头开始重建情节提要场景。
Eric Goldberg 2014年

84

如果使用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像素。

希望这个可以对您有所帮助。


2
Beber,是否一定要同时做这两个事情(选中“自定义”并在情节提要中编辑“行高”值,并在heightForRowAtIndexPath中指定它)?
marciokoko

您能帮我吗?我需要具有动态高度的动态单元格,但是如果使用此方法,无论返回什么,所有单元格都将消失。除了iPhone 5以外,该设备均可按预期运行。你能明白为什么吗?
Ostmeistro

34

对于动态单元格,rowHeight在上设置UITableView总是会覆盖单个单元格的rowHeight

IMO,此行为是一个错误。每当您必须在两个位置管理UI时,都容易出错。例如,如果您在情节提要中更改单元格大小,则还必须记住在情节提要中进行更改heightForRowAtIndexPath:。在Apple修复该错误之前,当前的最佳解决方法是重写heightForRowAtIndexPath:,但使用情节提要中的实际原型单元来确定高度,而不是使用幻数。这是一个例子:

- (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。


2
我已经发布了包含完整代码的答案,包括缓存;参见stackoverflow.com/a/16881312/292166
JosephH 2013年

1
哇哇哇!我赞成回答,但是要当心!如@Brennan在评论中所述,此方法不仅会导致性能下降,还会导致每次reloadData内存分配的增长,例如内存泄漏!需要使用上述lensovet的解决方法!花一天的时间来捕捉这种内存泄漏!
skywinder 2014年

在swift中不起作用,因为cell.bounds.size.height始终返回0.0
King-Wizard

1
在系统调用tableView:heightForRowAtIndexPath方法时,这些单元格还不存在。您应该能够使用传递给您的indexPath来索引数据模型,并查看在那里将使用哪种单元格,然后计算该单元格的高度并将其返回。这使系统可以在创建任何单元之前布置表中的单元。
King-Wizard

1
另外,您不应调用自己的cellForRowAtIndexPath方法。表格视图具有cellForRowAtIndexPath方法,如果当前在屏幕上可见该索引路径,它将返回该索引路径的单元格,但通常该索引路径没有与之关联的单元格。
King-Wizard

22

我已经构建了各种答案/注释提示的代码,因此该代码适用于使用原型单元的情节提要。

这段代码:

  • 不需要在情节提要中的明显位置以外的任何位置设置像元高度
  • 出于性能原因缓存高度
  • 使用通用函数获取索引路径的单元格标识符,以避免逻辑重复

感谢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...>

我知道这是一个旧答案,但是是否有人发现这会导致堆栈溢出?当视图加载时,我得到UISectionRowData refreshWithSection:tableViewRowData:调用tableView:heightForRowAtIndexPath:调用dequeueReusableCellWithIdentifier:调用[UISectionRowData ...],所以递归堆栈溢出。我确实想使用此解决方案,但它似乎不适用于iOS7。
sbaker

在swift中不起作用,因为cell.bounds.size.height始终返回0.0
King-Wizard

在系统调用tableView:heightForRowAtIndexPath方法时,这些单元格还不存在。您应该能够使用传递给您的indexPath来索引数据模型,并查看在那里将使用哪种单元格,然后计算该单元格的高度并将其返回。这使系统可以在创建任何单元之前布置表中的单元。
King-Wizard

另外,您不应调用自己的cellForRowAtIndexPath方法。表格视图具有cellForRowAtIndexPath方法,如果当前在屏幕上可见该索引路径,它将返回该索引路径的单元格,但通常该索引路径没有与之关联的单元格。
King-Wizard

@ snow-tiger我没有快速尝试过,但是我不理解您的评论。我不会“调用我自己的cellForRowAtIndexPath方法”,这是故意的,我没有。我还知道在调用tableView:heightForRowAtIndexPath时这些单元格不存在,这就是这段代码的全部重点,以及为什么它使用dequeueReusableCellWithIdentifier来获取一个单元格。此答案中发布的代码有效。快速进行一些额外操作,快速转换中发生一些不正确的操作,或者试图解决此问题/答案所针对的其他问题。
JosephH

19

实际上,您需要在两个地方更改行高,首先是单元格(您已经做了更改),然后选择“表格视图”并检查“大小”检查器


在tableview(不是cellview)中>在大小检查器选项卡中>行高
iman kazemayni

每当我忘记这个细节时,我都会发疯。不知道为什么使用情节提要板时调整单元格不会自动更新tableView!
踏板车

11

我认为这是一个错误。

尝试不通过实用程序检查器而是直接在情节提要上拖动鼠标来调整高度。

我用这种方法解决了这个问题。


10

如果您使用的是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
Andy Chou

7

您可以在以下几行的帮助下从情节提要中获取UITableviewCell的高度(在UITableviewController-静态单元格中)。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
   CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];

    return height;
}

6

在XML视图中打开情节提要,然后尝试编辑 rowHeight所需元素属性。

当我尝试为原型行设置自定义rowHeight时,它对我有用。它不能通过检查器运行,但是可以通过XML运行。


1
我右键单击并选择“打开为”->“源代码”。rowHeight已经设置为120。我相信情节提要在这里有一个错误,它会忽略自定义单元格的高度。
zirinisp 2012年

6

您可以将原型cells与自定义一起使用height,然后调用cellForRowAtIndexPath:并返回其frame.height。:。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self tableView:tableView
                    cellForRowAtIndexPath:indexPath];
    return cell.frame.size.height;
}

此方法的添加效果很好,并且现在将所有自定义项保留在情节提要中。
daspianist 2013年

迄今为止最好的解决方案
TheJeff


4

我最近一直在为此而努力。我的问题是上面使用heightForRowAtIndexPath:方法适用于Simulator中的iOS 7.1,但是只需切换到iOS 8.1,就可以完全。

我开始阅读有关自定义单元的更多信息(在iOS 8中引入,请点击此处)。显然,UITableViewAutomaticDimension在iOS 8中使用会有所帮助。我尝试使用该技术并删除了对heightForRowAtIndexPath:和voila 的使用,现在它在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)

2

使用Swift 4XCode 9上工作时,发生了相同的问题。

为单元格内的UI元素添加自动布局,自定义单元格行高将按照指定的方式工作。


1
嗨,请问您是怎么​​做到的?
Back Packer

您只需要在单元格底部添加一个约束集即可。
贾斯汀

当我这样做并在情节提要中选择“自动”作为单元格高度时,它希望将情节提要中的所有高度设置为44,尽管我在跑步时看起来正确。如何使情节提要正确显示?
大卫,

1

对于动态单元格,在UITableView上设置的rowHeight始终会覆盖单个单元格的rowHeight。如果行内的内容仅计算动态高度。


0

我能找到的唯一真正的解决方案是

- (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;
}

这可以正常工作,并且不会造成可怕的切换/如果复制了StoryBoard中已经存在的逻辑。不确定性能,但我猜想是什么时候进来的cellForRow:已经初始化的单元,速度就一样快。当然,这里可能会有附带损害赔偿,但看起来对我来说很好。

我也在这里发布了此内容:https : //devforums.apple.com/message/772464

编辑:奥尔特温·根茨提醒我,heightForRowAtIndexPath:将被称为所有 TableView的单元,而不仅仅是可见的单元格。听起来合乎逻辑,因为iOS需要知道总高度才能显示正确的滚动条。这意味着在较小的TableViews(例如20个单元格)上可能还不错,但在1000个Cell TableView上却忘了它。

同样,使用XML的先前技巧:与对我的第一条评论相同。正确的值已经在那里。


0

作为评论添加,但作为可见性的答案发布:

如果最初将表视图设置为“静态单元格”,然后将其更改为“动态原型”,那么似乎也存在问题。我有一个问题,即使是委托方法heightForRowAtIndexPath也被忽略了。我首先通过直接编辑情节提要XML来解决该问题,然后才从头开始使用动态原型从头开始重建情节提要场景。


0

鉴于我没有通过Interface Builder找到任何解决方案,所以即使最初的问题要求通过Interface Builder解决,我还是决定使用两个动态单元格Swift中发布程序化解决方案。无论如何,我认为这对于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)]!
   }

   ...

  }

一切都很好,但是除非我误读了代码,否则它仅依赖于幻数并且完全忽略了您在IB中为动态单元格设置的任何值,因此...这并不是OP问题的解决方案
Danny

0

您可以做的另一件事是转到文档大纲,选择嵌套了原型单元的表格视图。然后在“大小”检查器上,将表格视图的“行高”更改为所需的值,然后取消选中“自动”框。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.