【问题标题】:Dynamic Type and Self-Sizing Cells with Static Table带有静态表的动态类型和自定尺寸单元
【发布时间】:2016-01-02 11:31:46
【问题描述】:

我有一个典型的 master-detail 应用程序,它允许用户浏览对象的滚动列表,然后使用 push segue 钻取任何特定对象的详细信息。滚动主列表是使用原型单元格构建的 UITableView,细节场景是具有固定数量的部分和单元格的静态 UITableView。

我想在我的应用程序中实现动态类型和自动调整大小的单元格,以便用户可以更改基本字体大小。到目前为止,我已经成功地使用原型单元格的滚动列表制作了自我调整大小的单元格:通过使用自动布局,将每个标签中的行数设置为 0,并设置tableView.rowHeight = UITableViewAutomaticDimension,每个原型单元格的高度都会增加或缩小以适应文本的大小。

但我无法在我的静态表格视图中实现相同的效果。无论我使用自定义单元格还是内置单元格类型,字体都会增大/缩小,但单元格高度不会。

所以我的问题实际上是两个问题:1) 是否可以在静态表格视图中实现自动调整单元格,就像我对原型表格视图所做的那样? 2)如果第一个问题的答案是否定的,我该如何编写代码来测量静态表格视图单元格中标签的高度并适当调整单元格高度?

谢谢!

【问题讨论】:

    标签: ios swift uitableview ios9


    【解决方案1】:

    静态表视图返回在 Interface Builder 中设置的行高。 tableView.rowHeight 设置似乎被完全忽略了。这显然是 UIKit 中的一个错误。

    为了解决这个问题,只需覆盖 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 并返回 UITableViewAutomaticDimension

    【讨论】:

    • 你可以设置tableView.rowHeight而不是使用委托函数吗?
    • 抱歉,我只使用过程序化视图并没有意识到这一点。
    • XCode 9.3,2018 年中 - 仍然存在此错误。 heightForRowAtIndexPath 的解决方法有效。
    • Xcode 10.1 和 iOS 12.1,自调整单元格适用于静态表格视图。无需重写 heightForRowAtIndexPath 和estimatedHeightForRowAtIndexPath 方法。默认情况下,Interface Builder 中的行高和估计行高设置为“自动”。
    【解决方案2】:

    首先在你的类中添加这两个函数

    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
    
    func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
    

    其次,为了使 UITableViewAutomaticDimension 正常工作,请确保您已添加所有与单元格容器视图相关的左侧、右侧、底部和顶部约束。另外不要忘记将标签的行数设置为零。

    【讨论】:

      【解决方案3】:

      由于这是一个静态表,您无法将单元格出列,因此您必须为它们创建 IBOutlets,我会将它们保存在这样的数组中:

      @IBOutlet var cells: [UITableViewCell]!  
      

      然后你将不得不实现 heightForRowAtIndexPath 并计算大小:

      var rowSizes: [Int: CGFloat] = [:]
      
      override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
          return calculateHeightForCell(indexPath)
      }
      
      func calculateHeightForCell(indexPath: NSIndexPath) -> CGFloat {
      
          // check if we already calculated the height
          if let height = rowSizes[indexPath.row] {
              return height
          }
      
          // else, calculate it
          let cell = cells[indexPath.row]
      
          let size = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
      
          rowSizes[indexPath.row] = size.height
      
          return size.height
      }
      

      rowSizes 就像缓存一样,它将保存行高,因此它们只会被计算一次。更改字体大小时,只需清空 rowSizes 并刷新表格,以便再次计算它们。

      【讨论】:

        【解决方案4】:

        感谢您为昨天发布的问题提供的答案。不幸的是(可能是因为我自己作为 iOS 程序员的经验不足)我无法使 systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) 方法起作用。然而,经过反复试验,我发现了另一种似乎可行的方法:

        import UIKit
        
        class MasterTVC: UITableViewController {
            @IBOutlet weak var staticCustomCellLabel: UILabel!
        
            //viewDidLoad
            override func viewDidLoad() {
                super.viewDidLoad()
        
                self.tableView.estimatedRowHeight = 44.0
        
                staticCustomCellLabel.text = "This is the text for the static custom cell label; This is the text for the static custom cell label; This is the text for the static custom cell label"
        
                //Register handleDynamicTypeChange in observer: self
                NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleDynamicTypeChange:", name: UIContentSizeCategoryDidChangeNotification, object: nil)
            }
        
            //deinit
            deinit {
                NSNotificationCenter.defaultCenter().removeObserver(self)
            }
        
            //handleDynamicTypeChange
            //called when user changes text size in Settings > General > Accessibility > Larger Text
            //or Settings > Display & Brightness > Text Size
            func handleDynamicTypeChange(notification: NSNotification) {
                staticCustomCellLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
        
                self.tableView.reloadData()
            }
        
            //tableView:heightForRowAtIndexPath
            override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
                return UITableViewAutomaticDimension
            }
        }
        

        在故事板方面,设置从具有以下属性的单个表视图控制器开始:

        • 类:MasterTVC(我的自定义类);
        • 指定初始视图控制器;
        • 内容:静态单元格;
        • 样式:分组
        • 章节:1.

        第 1 节:

        • 行数:1.

        表格视图单元格:

        • 样式:自定义(在此处使用 Basic 会导致标签在设置中更改文本大小时消失);
        • 包含 UILabel。

        UILabel 进一步配置为:

        • 字体:正文(动态类型样式);
        • 行数:0;
        • 固定在内容视图的顶部、底部、左侧和右侧边缘的所有四个侧面(我使用了各自的约束 8、8、15、15);
        • 在自定义类代码中带有 @IBOutlet。

        这对我在 Xcode 7 和 Swift 2 中设计 iOS 9 并启用自动布局很有用。有趣的是,如果去掉用于立即响应文本大小变化的 NSNotificationCenter 代码,自调整单元格代码基本上是两行:在 viewDidLoad 中设置estimatedRowHeight,并从 tableView:heightForRowAtIndexPath 返回 UITableViewAutomaticDimension。

        基于这些结果,我相信我最初问题的答案是:1)是的;和 2) 见 1.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-11-28
          • 2012-07-11
          • 2019-12-04
          • 2016-07-13
          • 1970-01-01
          • 1970-01-01
          • 2019-10-09
          • 1970-01-01
          相关资源
          最近更新 更多