iOS9,为什么在dequeueReusableCellWithIdentifier中调用自定义UITableViewCell的layoutSubviews:forIndexPath如果使用了systemLayoutSizeFittingSize

时间:2015-12-30 06:59:52

标签: ios uitableview

  

我的问题的更具体的描述:在iOS9中,layoutSubviews调用我的自定义UITableViewCell的dequeueReusableCellWithIdentifier:forIndexPath,如果systemLayoutSizeFittingSize用于计算heightForRowAtIndexPath中的单元格高度?

     

因此,在layoutSubviews返回之前调用cellForRowAtIndexPath:,我无法再使用layoutSubviews来确定该单元格是否在屏幕上,并且有几个约束处理的问题。

对于复杂的自定义UITableViewCells,我更倾向于使用layoutSubview方法来计算和应用约束后运行的代码。 由于自定义UITableViewCell是复杂,我使用systemLayoutSizeFittingSize中的tableView:heightForRowAtIndexPath来通过自动布局计算高度。 这在iOS8中完美运行,但在iOS9中已经破解。

为了找出根本原因,我做了一个最小的项目,包括一个自定义的UITableViewCell,它有一个带有约束集的自定义标签:

class testCell : UITableViewCell {

    @IBOutlet weak var labelTest: UILabel!

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        print("testCell - init:coder")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        print("testCell - layoutSubviews ")
    }

    func setLabelText(text : String) {
        self.labelTest?.text = text
    }
}

和tableView的dataSource:

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 1
}

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    if let cell = tableView.dequeueReusableCellWithIdentifier("testCell") as? testCell {
        cell.setLabelText(String(indexPath.row))
        print(" tableview systemLayoutSizeFittingSize for \(indexPath.row)")
        let size = cell.systemLayoutSizeFittingSize(CGSizeMake(tableView.bounds.size.width, 1))
        return size.height
    }

    return 0
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let char = indexPath.row > 0 ? "" : ""
    print(char+char+char+char+char+char+char+char+char+char+char+char+char+char+char+char+char+char)
    print("tableview start... dequeueReusableCellWithIdentifier for \(indexPath.row)")
    let cell = tableView.dequeueReusableCellWithIdentifier("testCell", forIndexPath: indexPath)
    print("tableview end... dequeueReusableCellWithIdentifier for \(indexPath.row)")
    print(char+char+char+char+char+char+char+char+char+char+char+char+char+char+char+char+char+char)
    if let cell = cell as? testCell {
        cell.setLabelText(String(indexPath.row))
    }
    return cell
}

日志显示在dequeueReusableCellWithIdentifier中调用layoutSubviews:forIndexPath

  

testCell - init:编码器
   tableview systemLayoutSizeFittingSize为0
  testCell - init:编码器
   tableview systemLayoutSizeFittingSize为0
  testCell - init:编码器
   tableview systemLayoutSizeFittingSize为0
  testCell - init:编码器
   tableview systemLayoutSizeFittingSize为0
  
  tableview start ... dequeueReusableCellWithIdentifier为0
  testCell - init:编码器
  testCell - init:编码器
   tableview systemLayoutSizeFittingSize为0
  testCell - layoutSubviews
  tableview end ... dequeueReusableCellWithIdentifier为0
  
  testCell - init:编码器
   tableview systemLayoutSizeFittingSize为0
  testCell - layoutSubviews

让我们关注以下两行之间的日志:

  

tableview start ... dequeueReusableCellWithIdentifier for 0
  testCell - init:编码器
  testCell - init:编码器
   tableview systemLayoutSizeFittingSize为0
  testCell - layoutSubviews
  tableview end ... dequeueReusableCellWithIdentifier for 0

  • 分析:
        *第一个 testCell - init:coder dequeueReusableCellWithIdentifier:forIndexPath调用,由cellForRowAtIndexPath调用     *第二个 testCell - init:coder dequeueReusableCellWithIdentifier调用,由heightForRowAtIndexPath调用     *我在 testCell - layoutSubviews 设置了一个断点,并确认它由dequeueReusableCellWithIdentifier:forIndexPath调用cellForRowAtIndexPath

  • 由此得出结论:
    由于未知原因,layoutSubviews

  • 中的dequeueReusableCellWithIdentifier:forIndexPath会调用自定义UITableViewCell的cellForRowAtIndexPath:

寻找解决方案

  1. 第一个解决方案在于功能:heightForRowAtIndexPath:
    如果我手动计算单元格的高度而不是使用systemLayoutSizeFittingSize,它就可以了! layoutSubviews无法呼叫dequeueReusableCellWithIdentifier:forIndexPath 但是这种方法并不方便,因为细胞高度的计算可能太复杂了 以下是修改后的代码和日志:

    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 100 // might be a very complex calculation
    }
    
      


      tableview start ... dequeueReusableCellWithIdentifier为0
      testCell - init:编码器
      tableview end ... dequeueReusableCellWithIdentifier为0
      
      testCell - layoutSubviews

  2. 第二个解决方案在于功能:cellForRowAtIndexPath:
    我尝试使用dequeueReusableCellWithIdentifier代替dequeueReusableCellWithIdentifier:forIndexPath,下面的日志显示layoutSubviews未直接在dequeueReusableCellWithIdentifier中调用,但仍会在tableView:_configureCellForDisplay中调用({1}}不确定时间)。我无法确认它是否是一种解决方案 无论如何,dequeueReusableCellWithIdentifier:forIndexPathdequeueReusableCellWithIdentifier以外的推荐方法。如果我愿意,我仍然更喜欢前者。

      

    testCell - init:编码器
       tableview systemLayoutSizeFittingSize为0
      testCell - init:编码器
       tableview systemLayoutSizeFittingSize为0
      testCell - init:编码器
       tableview systemLayoutSizeFittingSize为0
      testCell - init:编码器
       tableview systemLayoutSizeFittingSize为0
      
      tableview start ... dequeueReusableCellWithIdentifier为0
      testCell - init:编码器
      tableview end ... dequeueReusableCellWithIdentifier为0
      
      testCell - init:编码器
       tableview systemLayoutSizeFittingSize为0
      testCell - layoutSubviews
      testCell - layoutSubviews

  3. 问题:

    虽然我找到了2个解决方案,但它们都不令人满意 最好的方法是我仍然可以使用systemLayoutSizeFittingSize来计算单元格高度,并使用dequeueReusableCellWithIdentifier:forIndexPath来获取有效单元格。
    唯一的问题是我需要确认layoutSubviews在函数cellForRowAtIndexPath返回之前未被调用(在当前情况下,它由函数返回之前由dequeueReusableCellWithIdentifier:forIndexPath调用cellForRowAtIndexPath),以便我可以将此方法用于在计算和应用单元格约束
    后运行的代码,并且可以在到达layoutSubviews时确认细胞已经在屏幕上 有没有人有任何好主意?
    谢谢。

0 个答案:

没有答案