【问题标题】:Custom Cell Row Height setting in storyboard is not responding故事板中的自定义单元格行高设置没有响应
【发布时间】:2012-01-26 19:15:04
【问题描述】:

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

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

【问题讨论】:

    标签: ios uitableview ios5 storyboard xcode4.2


    【解决方案1】:

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

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

    【讨论】:

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

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

    【讨论】:

      【解决方案3】:

      我最近一直在努力解决这个问题。我的问题是上面使用 heightForRowAtIndexPath: 方法发布的解决方案适用于模拟器中的 iOS 7.1,但随后通过简单地切换到 iOS 8.1 就完全搞砸了结果。

      我开始阅读有关自调整单元格的更多信息(在 iOS 8 中引入,read here)。很明显,UITableViewAutomaticDimension 的使用在 iOS 8 中会有所帮助。我尝试使用该技术并删除了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)
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

          • 添加此方法效果很好,现在将所有自定义内容保留在情节提要中应有的位置。
          • 迄今为止最好的解决方案
          【解决方案6】:

          如果您使用的是 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
          【解决方案7】:

          鉴于我没有通过 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的问题
          【解决方案8】:

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

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

          【讨论】:

            【解决方案9】:

            如果你想设置一个静态的行高,你可以这样做:

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

            【讨论】:

              【解决方案10】:

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

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

              【讨论】:

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

              如果你使用 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 设备,它可以按预期工作。你能理解为什么吗?
              【解决方案12】:

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

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

              【讨论】:

                【解决方案13】:

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

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

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

                【讨论】:

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

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

                这段代码:

                • 不要求将单元格高度设置为故事板中明显位置以外的任何位置
                • 出于性能原因缓存高度
                • 使用通用函数获取索引路径的单元格标识符以避免重复逻辑

                感谢 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 我没有快速尝试过这个,但我不明白你的 cmets。我不“调用 [我的] 自己的 cellForRowAtIndexPath 方法”,我故意不这样做。我也知道在调用 tableView:heightForRowAtIndexPath 时单元格不存在,这就是这段代码的重点,以及为什么它使用 dequeueReusableCellWithIdentifier 来获取单元格。此答案中发布的代码有效。要么在 swift 中发生了一些额外的事情,要么在 swift 转换中有一些不正确的事情,或者正在尝试解决这个问题/答案所针对的不同问题。
                【解决方案15】:

                我认为这是一个错误。

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

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

                【讨论】:

                  【解决方案16】:

                  对于动态单元格,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
                  • 哇-哇-哇!我赞成答案,但请注意!这种方法不仅会导致性能下降,正如 cmets 中的@Brennan 所说,它还会导致每次 reloadData 时内存分配增加,例如内存泄漏!需要使用上面lensovet的解决方法!花一天的时间来捕捉这个内存泄漏!
                  • 在 Swift 中不起作用,因为 cell.bounds.size.height 总是返回 0.0
                  • 在系统调用您的 tableView:heightForRowAtIndexPath 方法时,这些单元格还不存在。您应该能够使用传递给您的 indexPath 来索引您的数据模型并查看将在那里使用哪种单元格,然后计算该单元格的高度并返回它。这使系统能够在创建任何单元格之前对表格中的单元格进行布局。
                  • 另外,您不应该调用自己的 cellForRowAtIndexPath 方法。表格视图有一个 cellForRowAtIndexPath 方法,如果该索引路径当前在屏幕上可见,它将返回该索引路径的单元格,但通常该索引路径没有与之关联的单元格。
                  【解决方案17】:

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

                  - (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 提醒我 heightForRowAtIndexPath: 将为 TableView 的 所有 单元格调用,而不仅仅是可见的单元格。听起来合乎逻辑,因为 iOS 需要知道总高度才能显示正确的滚动条。这意味着它在小型 TableView(如 20 个单元格)上可能没问题,但在 1000 个单元格的 TableView 上就忘了。

                  此外,之前的 XML 技巧:与我的第一条评论相同。正确的值已经存在。

                  【讨论】:

                    【解决方案18】:

                    实际上有两个地方需要更改为行高,首先是单元格(您已经更改了) 现在选择 Table View 并检查 Size Inspector

                    【讨论】:

                    • 在表格视图中(不是单元格视图)> 在尺寸检查器选项卡中 > 行高
                    • 每次忘记这个细节都会让我发疯。不知道为什么在使用情节提要时调整单元格不会自动更新 tableView!
                    猜你喜欢
                    • 1970-01-01
                    • 2012-09-26
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-12-24
                    • 2012-01-08
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多