在UITableViewCell中加载UIView的Nib文件不能拉伸

我有一个可以通过nib / xib文件重用的UIView。 我想加载这个,并填写一个UITableViewCell这是一个自我调整UITableView中使用。 所有与自动布局。

大多数工程很好,但似乎加载UIView使用附加的约束,缩小UITableViewCell的contentView。 这对身高是有好处的,但是我不想要这个宽度。

UITableViewCell的外观 忽略下面的灰色单元格,这只是一个选定的单元格。

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cellId = "RowView0002" var cell = tableView.dequeueReusableCell(withIdentifier: cellId) if cell == nil { cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: cellId) let subView = RowView(frame: cell!.frame) cell!.contentView.attachViewWithConstraints(subView) let _ = subView.viewLoadedFromNibAttached(name: cellId) } return cell! } override public func viewDidLoad() { super.viewDidLoad() tableView.delegate = self tableView.dataSource = self tableView.estimatedRowHeight = 40.0 tableView.rowHeight = UITableViewAutomaticDimension } extension UIView { public func attachViewWithConstraints(_ view:UIView) { addSubview(view) view.translatesAutoresizingMaskIntoConstraints = false view.layoutAttachAll(to: self) } @discardableResult public func viewLoadedFromNibAttached<T : UIView>(name:String) -> T? { guard let view = Bundle.main.loadNibNamed(name, owner: self, options: nil)?[0] as? T else { return nil } attachViewWithConstraints(view) return view } public func layoutAttachAll(to childView:UIView) { var constraints = [NSLayoutConstraint]() childView.translatesAutoresizingMaskIntoConstraints = false constraints.append(NSLayoutConstraint(item: childView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0)) constraints.append(NSLayoutConstraint(item: childView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0)) constraints.append(NSLayoutConstraint(item: childView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0)) constraints.append(NSLayoutConstraint(item: childView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0)) childView.addConstraints(constraints) } 

在RowView0002.xib中,我已经将rootviews背景设置为红色,并在边上添加了一个带有4个约束的UILabel。 我都试图设置rootView的类RowView以及它的文件的所有者。 两个“作品”。

任何想法如何让contentView匹配UITableView?

*编辑1:绿色是UILabel的背景。 红色是笔尖文件的背景。 在运行应用程序后,View heirarcy是:UITableViewCell> ContentView> RowView> NibFileView(红色)> UILabel(绿色)

检查视图层次结构显示所有约束都按预期设置。 但是,UITableViewContentView具有与所看到的总大小(错误)匹配的约束:

 self.width = 156.5 @ 1000 

layoutAttachAll的完整实现如下。

一些用法示例:

  // pin all edge to superview myView.layoutAttachAll() // pin all edges (to superview) with margin: myView.layoutAttachAll(margin: 8.0) // for child views: pin leading edge to superview's leading edge: myView.layoutAttachLeading() // for sibling views: pin leading edge to siblingView's trailing edge: myView.layoutAttachLeading(to: siblingView) // for sibling views: pin top edge to siblingView's bottom edge: myView.layoutAttachTop(to: siblingView) 

注意: 使用这些方法附加到超级视图之前,必须将myView添加为子视图。 此外,所有参与的视图必须设置translatesAutoresizingMaskIntoConstraints = false。

全面实施:

 import UIKit extension UIView { /// attaches all sides of the receiver to its parent view func layoutAttachAll(margin : CGFloat = 0.0) { let view = superview layoutAttachTop(to: view, margin: margin) layoutAttachBottom(to: view, margin: margin) layoutAttachLeading(to: view, margin: margin) layoutAttachTrailing(to: view, margin: margin) } /// attaches the top of the current view to the given view's top if it's a superview of the current view, or to it's bottom if it's not (assuming this is then a sibling view). /// if view is not provided, the current view's super view is used @discardableResult func layoutAttachTop(to: UIView? = nil, margin : CGFloat = 0.0) -> NSLayoutConstraint { let view: UIView? = to ?? superview let isSuperview = view == superview let constraint = NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: view, attribute: isSuperview ? .top : .bottom, multiplier: 1.0, constant: margin) superview?.addConstraint(constraint) return constraint } /// attaches the bottom of the current view to the given view @discardableResult func layoutAttachBottom(to: UIView? = nil, margin : CGFloat = 0.0, priority: UILayoutPriority? = nil) -> NSLayoutConstraint { let view: UIView? = to ?? superview let isSuperview = (view == superview) || false let constraint = NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: isSuperview ? .bottom : .top, multiplier: 1.0, constant: -margin) if let priority = priority { constraint.priority = priority } superview?.addConstraint(constraint) return constraint } /// attaches the leading edge of the current view to the given view @discardableResult func layoutAttachLeading(to: UIView? = nil, margin : CGFloat = 0.0) -> NSLayoutConstraint { let view: UIView? = to ?? superview let isSuperview = (view == superview) || false let constraint = NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal, toItem: view, attribute: isSuperview ? .leading : .trailing, multiplier: 1.0, constant: margin) superview?.addConstraint(constraint) return constraint } /// attaches the trailing edge of the current view to the given view @discardableResult func layoutAttachTrailing(to: UIView? = nil, margin : CGFloat = 0.0, priority: UILayoutPriority? = nil) -> NSLayoutConstraint { let view: UIView? = to ?? superview let isSuperview = (view == superview) || false let constraint = NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: isSuperview ? .trailing : .leading, multiplier: 1.0, constant: -margin) if let priority = priority { constraint.priority = priority } superview?.addConstraint(constraint) return constraint } } 

看起来问题是用UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: cellId)创build的单元格UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: cellId)没有关于表视图宽度的信息,所以它根据标签的宽度自动resize。 显然,表格视图/单元格不会强制单元格的内容视图占据其宽度。

你可能想要重做一些这种细胞处理代码。

如果你想从xib载入你的单元格,你可以跳过一切约束。 只要执行:

  override func viewDidLoad() { //... let nib = UINib(nibName: "RowView0002", bundle: NSBundle.main) tableView.reigsterNib(nib, forCellReuseIdentifier: "RowView0002") } 

非常重要:.xib文件中的第一个顶级项目必须是UITableViewCell。 Nib默认为UIViews,删除IB中的视图并从IB右下angular的对象库拖动一个UITableViewCell。 然后,如果需要,将其子类设置为您创build的UITableViewCell子类。 (您可能还需要在IB中设置reuseIdentifier。)

然后在tableView(_:cellForRowAt IndexPath:)

 guard let cell = tableView.dequeueResuableCell(withIdentifier: "RowView0002", for: indexPath) as? TheNibUITableViewSubclass else { //something went wrong, probably crash } cell.label.text = //... return cell 

你可能会想把这个“RowView0002”放在一个常量的地方。

如果“RowView0002”和RowView类都需要视图,则应该创buildUITableViewCell的子类。 覆盖只是init(style:resueIdentifier:) and after calling超级init(style:resueIdentifier:) and after calling ,在上面的代码中添加您的子视图。 希望这可以帮助!

这是正确的layoutAttachAll

 public func layoutAttachAll(to parentView:UIView) { var constraints = [NSLayoutConstraint]() self.translatesAutoresizingMaskIntoConstraints = false constraints.append(NSLayoutConstraint(item: self, attribute: .left, relatedBy: .equal, toItem: parentView, attribute: .left, multiplier: 1.0, constant: 0)) constraints.append(NSLayoutConstraint(item: self, attribute: .right, relatedBy: .equal, toItem: parentView, attribute: .right, multiplier: 1.0, constant: 0)) constraints.append(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: parentView, attribute: .top, multiplier: 1.0, constant: 0)) constraints.append(NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: parentView, attribute: .bottom, multiplier: 1.0, constant: 0)) parentView.addConstraints(constraints) } 

我通过添加一个匹配tableViews宽度的宽度约束来解决这个问题。 这是来自CustomTableViewCell的代码:

 public override func layoutSubviews() { super.layoutSubviews() if let width = tableView()?.frame.width, !haveAddedWidthConstraint { haveAddedWidthConstraint = true rowView.addWidthConstraint(width: width) } } 

UIViewExtension:

 public func addWidthConstraint(width: CGFloat) { let widthConstraint = NSLayoutConstraint(item: self, attribute: .width, relatedBy: .greaterThanOrEqual, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: width) widthConstraint.priority = 1000 addConstraint(widthConstraint) } 

UITableViewCellExtension:

 func tableView() -> UITableView? { var currentView: UIView = self while let superView = currentView.superview { if superView is UITableView { return (superView as! UITableView) } currentView = superView } return nil }