ChatGPT解决这个技术问题 Extra ChatGPT

故事板中的自定义单元格行高设置没有响应

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

如果我更改表格视图的“行大小”,那么所有单元格的大小都会更改。我不想这样做,因为我只想要一个单元格的自定义大小。我看过很多帖子都有解决问题的方案,但如果可能的话,我更愿意通过情节提要来解决。


p
pixelfreak

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

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

不确定这是否是一个错误,Apple 可能是故意这样做的?


正确答案#3,特别是因为这个答案适用于 Interface Builder/Storyboards。如果您选择 IB 中的单元格,则 Size Inspector 会在顶部显示行高(带有“自定义”复选框),但如果您选择整个表格视图,则 Size Inspector 也会在顶部显示行高(没有“自定义” “ 在这种情况下)。正如pixelfreak所说,只有表格视图设置用于动态单元格。 (不知道是不是故意的)
这个答案意味着解决方案只是将 UITableView 内容从 Dynamic Prototypes 更改为 Static Cells,我这样做了,我的整个项目爆炸了.. 我自己差点被杀。
有没有办法找回这个号码?深入挖掘它的唯一方法是潜入故事板并从那里拉出来吗?
这绝对不是错误,因为您的表格是动态的,那么系统怎么知道您去哪里使用这些单元格中的每一个?以及每个原型将使用多少次。
如果您最初将表格视图设置为“静态单元格”,然后将其更改为“动态原型”,这似乎也存在问题。我遇到了一个问题,即使是 rowHeight 的委托方法也被忽略了。我首先通过直接编辑情节提要 XML 来解决它,然后最后只是从头开始重建情节提要场景,从一开始就使用动态原型。
P
Peter Mortensen

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

我希望这个可以帮助你。


Beber,一个人总是必须同时做这两个(检查自定义并编辑故事板中的行高值&&在 heightForRowAtIndexPath 中指定它)?
你能帮我解决这个问题吗?我需要具有动态高度的动态单元格,但是如果我使用这种方法,无论我返回什么,所有单元格都会消失。除了 iPhone 5 上的设备,它可以按预期工作。你能明白为什么吗?
m
memmons

对于动态单元格,在 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:故事板。


我已经发布了包含缓存在内的完整代码的答案;见stackoverflow.com/a/16881312/292166
哇哇哇!我赞成答案,但请注意!正如@Brennan 在评论中所说,这种方法不仅会导致性能下降,还会导致每次 reloadData 时内存分配增加,例如内存泄漏!需要使用上面lensovet的解决方法!花一天的时间来捕捉这个内存泄漏!
在 Swift 中不起作用,因为 cell.bounds.size.height 总是返回 0.0
在系统调用您的 tableView:heightForRowAtIndexPath 方法时,这些单元格还不存在。您应该能够使用传递给您的 indexPath 来索引您的数据模型并查看将在那里使用哪种单元格,然后计算该单元格的高度并返回它。这使系统能够在创建任何单元之前对表格中的单元进行布局。
此外,您不应调用自己的 cellForRowAtIndexPath 方法。表视图有一个 cellForRowAtIndexPath 方法,如果该索引路径当前在屏幕上可见,它将返回该索引路径的单元格,但通常该索引路径没有与之关联的单元格。
J
JosephH

我已经构建了各种答案/评论提示的代码,以便这适用于使用原型单元的情节提要。

这段代码:

不需要将单元格高度设置在故事板中明显位置以外的任何位置

出于性能原因缓存高度

使用通用函数获取索引路径的单元格标识符以避免重复逻辑

感谢 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。
在 Swift 中不起作用,因为 cell.bounds.size.height 总是返回 0.0
在系统调用您的 tableView:heightForRowAtIndexPath 方法时,这些单元格还不存在。您应该能够使用传递给您的 indexPath 来索引您的数据模型并查看将在那里使用哪种单元格,然后计算该单元格的高度并返回它。这使系统能够在创建任何单元之前对表格中的单元进行布局。
此外,您不应调用自己的 cellForRowAtIndexPath 方法。表视图有一个 cellForRowAtIndexPath 方法,如果该索引路径当前在屏幕上可见,它将返回该索引路径的单元格,但通常该索引路径没有与之关联的单元格。
@snow-tiger 我没有快速尝试过,但我不明白你的评论。我不“调用 [我的] 自己的 cellForRowAtIndexPath 方法”,我故意不这样做。我也知道在调用 tableView:heightForRowAtIndexPath 时单元格不存在,这就是这段代码的重点,以及为什么它使用 dequeueReusableCellWithIdentifier 来获取单元格。此答案中发布的代码有效。要么在 swift 中发生了一些额外的事情,要么在 swift 转换中有一些不正确的东西,或者正在尝试解决这个问题/答案所针对的不同问题。
K
Kristjan H.

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


在 tableview(不是 cellview)中 > 在尺寸检查器选项卡中 > 行高
每次我忘记这个细节时都会让我发疯。不知道为什么在使用情节提要时调整单元格不会自动更新 tableView!
F
Fogni

我认为这是一个错误。

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

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


C
Chathuranga Silva

如果您使用的是 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
H
Hiren Panchal

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

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

    return height;
}

P
Peter Mortensen

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

当我尝试为我的原型行设置自定义 rowHeight 时,它对我有用。它不是通过检查器工作的,而是通过 XML 工作的。


我右键单击并选择“打开方式”->“源代码”。 rowHeight 已经设置为 120。我相信情节提要有一个错误,它忽略了自定义单元格高度。
P
P.J.Radadiya

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

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

添加此方法效果非常好,现在将所有自定义内容保留在情节提要中应有的位置。
迄今为止最好的解决方案
P
Peter Mortensen

如果要设置静态行高,可以执行以下操作:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 120;
}

s
shim

我最近一直在为此苦苦挣扎。我的问题是上面使用 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)

M
Murari Varma

使用 Swift 4 处理 XCode 9 时也出现了同样的问题。

为 Cell 内的 UI 元素添加 AutoLayout,自定义单元格行高将按照指定相应地工作。


你好,请问你是怎么做到的?
您只需在单元格底部添加一个约束集。
当我这样做并在情节提要中为单元格高度选择“自动”时,它希望在情节提要中将所有高度设置为 44,尽管它在我运行时看起来是正确的。如何让情节提要正确显示?
A
Ash

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


S
StuFF mc

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

- (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 的技巧:与我的第一条评论相同。正确的值已经存在。


E
Eric G

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

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


K
King-Wizard

鉴于我没有通过 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)]!
   }

   ...

  }

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

您可以做的另一件事是转到您的文档大纲,选择您的原型单元格嵌套的表格视图。然后在 Size Inspector 上,将 table view 的 Row Height 更改为所需的值并取消选中 Automatic 框。