添加和布局从 xib 加载的子视图到自定义单元格

Posted

技术标签:

【中文标题】添加和布局从 xib 加载的子视图到自定义单元格【英文标题】:Add and layout subviews loaded from xib to a custom cell 【发布时间】:2016-06-27 13:26:45 【问题描述】:

我有一个自定义单元格“CustomCell”,我希望根据自定义数据元素进行组合。 我正在尝试将子视图添加到 CustomCell 但对于从 xib (https://***.com/a/26326006/3546621) 加载的子视图,我无法弄清楚如何将它们布局到单元格的 contentView 中;即以编程方式设置框架或添加约束似乎有效。 (CustomCell 没有附加 xib,每个子视图都是以编程方式加载的。其中一些子视图是从 xib 加载的。)

例如,这是我的自定义单元格。它有两个子视图,一个用 UIView(frame: CGRect()) 初始化的黄色视图和一个用 UIView.fromNib 初始化的蓝色视图的正下方。

这是 BlueView.xib

我没有成功将 blueView 放在 yellowView 下面,而是将 blueView 堆叠在 yellowView 之上:

class CustomCell: UITableViewCell 

  let yellowView: UIView = UIView()
  let blueViewFromXib: BlueView = UIView.fromNib()

  override init(style: UITableViewCellStyle, reuseIdentifier: String?)
    super.init(style: style, reuseIdentifier: reuseIdentifier)
  

  required init?(coder aDecoder: NSCoder) 
    super.init(coder: aDecoder)
  

  fun configureForData(custom: Custom)

    yellowView.backgroundColor = UIColor.yellowColor()
    yellowView.translatesAutoresizingMaskIntoConstraints = false
    contentView.addSubview(yellowView)

    blueView.translatesAutoresizingMaskIntoConstraints = false
    contentView.addSubview(blueView)

    layoutIfNeeded()
  

  override func layoutSubviews() 
    super.layoutSubviews()
    let height = NSLayoutConstraint(item: contentView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 80)
    contentView.translatesAutoresizingMaskIntoConstraints = false
    contentView.addConstraint(height)

    yellowView.frame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: 40)

    // I want to add the blueView at the bottom of the yellowView

    // Option 1: not working
    blueView.frame = CGRect(x: 0, y: 40, width: contentView.frame.width, height: 40)

    // Option 2: not working
    let top = NSLayoutConstraint(item: blueView, attribute: .Top, relatedBy: .Equal, toItem: contentView, attribute: .Top, multiplier: 1, constant: 40)
    let bottom = NSLayoutConstraint(item: blueView, attribute: .Bottom, relatedBy: .Equal, toItem: contentView, attribute: .Bottom, multiplier: 1, constant: 0)
    let leading = NSLayoutConstraint(item: blueView, attribute: .Leading, relatedBy: .Equal, toItem: contentView, attribute: .Leading, multiplier: 1, constant: 0)
    let trailing = NSLayoutConstraint(item: blueView, attribute: .Trailing, relatedBy: .Equal, toItem: contentView, attribute: .Trailing, multiplier: 1, constant: 0)
    contentView.addConstraints([top, bottom, leading, trailing])
  


class BlueView: UIView 
  // the project includes a BlueView.xib which is simply a UIView whose background color is blue

视图控制器

override func viewDidLoad()
  super.viewDidLoad()
  tableView.delegate = self
  tableView.datasource = self
  tableView.rowHeight = UITableViewAutomaticDimension
  tableView.estimatedRowHeight = 80
  tableView.registerClass(CustomCell.self, forCellReuseIdentifier: "CustomCell")


func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
  let custom = customs[indexPath.row]
  let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomCell
  cell.configureForData(custom)
  return cell 

【问题讨论】:

如果您使用笔尖,您可以在那里布局视图。您是否有理由要手动执行此操作? @PEEJWEEJ 我知道如何自己布局子视图(即 nib 加载子视图的子视图)。但我没有成功将子视图布置到单元格的内容视图中。 您可以将视图添加到 nib 中的单元格并与 IBOutlets 连接 顺便说一句,您在 layoutSubviews 中设置框架的代码正在将它们设置为新的 UIView...甚至不应该编译 @PEEJWEEJ 请检查代码。自定义单元格没有 xib。我想以编程方式构建它。只有一些构成最终单元格的子视图是从 xib 加载的 【参考方案1】:

需要注意的几件事

    在 layoutSubviews 中,您不应该添加/删除不变的约束。如果您设置了约束,默认实现 (super.layoutSubviews()) 将根据约束调整大小/布局。

    如果您设置了约束,它们会覆盖任何已设置的框架。

    blueView.frame = UIView(frame: CGRect(x: 0, y: 40, width: contentView.frame.width, height: 40)) 甚至不应该编译。您正在将 blueView 的框架(CGRect)设置为 UIView 的新实例。

无论如何,您似乎正在为 blueView 使用 layoutConstraints,并为 YellowView 手动设置框架。我猜如果您使用其中之一,您将能够弄清楚发生了什么。

为简化操作,请尝试将您的子视图设置为可选项:

let yellowView: UIView?
let blueViewFromXib: BlueView?

然后注释掉layoutSubviews,使用这个:

func configureForData(custom: Custom)

    if yellowView == nil 
        yellowView = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.width, height: 40))
        yellowView?.backgroundColor = UIColor.yellowColor()
        self.addSubview(yellowView)
    
    if blueView == nil 
        blueView = BlueView.fromNib()
        blueView?.frame = CGRect(x: 0, y: 40, width: self.frame.width, height: 40)
        self.addSubview(blueView)
    

【讨论】:

3.是一个错字。刚改正。我一直在尝试只对黄色和蓝色视图使用约束,或者只对黄色和蓝色视图使用框架。没有成功。 添加了一个我认为应该可以工作的例子,但没有完全测试它。 它甚至没有编译,但是即使修复它,这个sn-p也没有解决问题

以上是关于添加和布局从 xib 加载的子视图到自定义单元格的主要内容,如果未能解决你的问题,请参考以下文章

从 Xib 加载原型单元

来自 XIB 的自定义 UIView 加载具有巨大规模的子视图

如何将 xib 的子视图显示到另一个 xib 的表格单元加载中

表格视图单元格高度动态 + 从 .xib 加载

我们可以将具有自动布局的 XIB 加载为以编程方式创建的没有自动布局的视图的子视图,并使用父视图调整子视图的大小吗?

Grid布局(四)单元格自定义布局