0

我有一个UIView,它可以通过nib/xib文件重复使用。我想加载这个并填充要在自调整大小的UITableView中使用的UITableViewCell。全部采用自动布局。在UITableViewCell中加载UIView的笔尖文件不能拉伸

大多数作品不错,但它看起来像加载的UIView使用它附加的约束来缩小UITableViewCell的contentView。这对身高有好处,但我不希望这个宽度。

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

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背景为红色,加一个UILabel与4个约束它的两侧一定的余量,你可以看到。我都尝试将rootView设置为类RowView以及它的文件所有者。这两个“作品”。

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

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

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

self.width = 156.5 @ 1000 
+0

为什么TVC分割线是在不同高度的你的意见结束了吗?看来你的视角占据的高度是单元高度的三倍。你确定这不重叠吗?尝试使用视图调试器检查尺寸 – Andrea

+0

忽略左侧的tableview。这是另一个UITableView。 – Sunkas

+0

有一些我不明白的东西,是你从xib看到的绿色吗? TVC contentView是红色的吗? – Andrea

回答

0

我通过还加入了宽度约束相匹配的宽度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 
} 
0

它看起来像问题是与UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: cellId)创建的细胞没有关于表视图的宽度信息,所以它是大小本身基于标签的宽度。显然,表格视图/单元格不会强制单元格的内容视图占据其宽度。

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

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

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

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

然后在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类都需要是视图,那么您应该创建一个UITableViewCell的子类。覆盖只是init(style:resueIdentifier:) and after calling超`添加您的子视图在上面的代码。希望这可以帮助!

+0

问题是我需要在UITableViewCell中没有使用的地方加载nib文件。所以我不能使用你的UITableViewCell作为我的nib文件中的根视图的建议。然而,我通过有一个额外的宽度约束来解决这个问题,该约束在放置在UITableViewCell中时延伸了视图。 – Sunkas

0

这是正确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) 
} 
1

完全实施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的必须添加作为一个子视图附接使用这些方法的SuperView之前。此外,所有参与的视图必须使用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 
    } 
} 
+0

这些只是帮助方法来设置顶部,底部,前导和尾随约束。我的layoutAttachAll已经在做这个。问题在于接受的答案描述了缺少宽度约束。 – Sunkas