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

Sun*_*kas 3 uitableview ios autolayout uitableviewautomaticdimension

我有一个可通过 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)
    }
Run Code Online (Sandbox Code Playgroud)

在 RowView0002.xib 中,我将 rootviews 背景设置为红色,向其两侧添加了一个带有 4 个约束的 UILabel,您可以看到它有一些边距。我都试图将 rootView 设置为类 RowView 以及它的文件所有者。两者都“有效”。

知道如何让 contentView 与 UITableView 匹配吗?

*编辑1:绿色是UILabel的背景。红色是 nib 文件的背景。运行应用程序后,视图继承关系是: UITableViewCell > ContentView > RowView > NibFileView(红色)> UILabel(绿色)

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

self.width = 156.5 @ 1000
Run Code Online (Sandbox Code Playgroud)

GK1*_*100 5

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)
Run Code Online (Sandbox Code Playgroud)

注意:使用这些方法附加到超级视图之前,必须将 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
    }
}
Run Code Online (Sandbox Code Playgroud)