以编程方式创建UITableViewCell约束

时间:2017-12-04 02:34:43

标签: ios swift uitableview constraints

这一切都发生在这个课程中:

class CustomCell2: UITableViewCell {

当我打印在Storyboard中设置的现有宽度约束(label = 0.7 *单元格宽度)的值时,我看到:

<NSLayoutConstraint:0x36b8750 UILabel:0x3d2aac0'Label'.width == 0.7*appName.CustomCell2:0x3e01880'CustomCell2'.width>

当我尝试以编程方式创建相同的约束时,我得到错误&#34;视图层次结构没有为约束准备:&#34;

<NSLayoutConstraint:0xee08590 UILabel:0x3d2aac0'Label'.width == 0.9*appName.CustomCell2:0x3e01880'CustomCell2'.width>

看起来完全一样,为什么不能添加这个约束?

CustomCell2的awakeFromNib()中的约束代码:

let widthConstraint = NSLayoutConstraint(item: labelName, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.width, multiplier: 0.9, constant: 0)
labelName.addConstraint(widthConstraint)

其余的错误信息:

When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.
2017-12-03 20:18:51.183 appName[899:684382] View hierarchy unprepared for constraint.
    Constraint: <NSLayoutConstraint:0xee08590 UILabel:0x3d2aac0'Label'.width == 0.9*appName.CustomCell2:0x3e01880'CustomCell2'.width>
    Container hierarchy: 
<UILabel: 0x3d2aac0; frame = (281 43; 674 54); text = 'Label'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x4233d30>>
    View not found in container hierarchy: <appName.CustomCell2: 0x3e01880; baseClass = UITableViewCell; frame = (0 0; 963 160); layer = <CALayer: 0xee08250>>
    That view's superview: NO SUPERVIEW
Unable to install constraint on view.  Does the constraint reference something from outside the subtree of the view?  That's illegal. constraint:<NSLayoutConstraint:0xee08590 UILabel:0x3d2aac0'Label'.width == 0.9*appName.CustomCell2:0x3e01880'CustomCell2'.width> view:<UILabel: 0x3d2aac0; frame = (281 43; 674 54); text = 'Label'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x4233d30>>

谢谢!

3 个答案:

答案 0 :(得分:1)

你应该在init中为单元格添加约束,假设它是一个出列的可重用单元格,记得使用contentView而不是View来查看单元格的边界:

class CustomCell2: UITableViewCell {

//MARK: Subviews
//Add View Programmatically or in xib
let titleLabel: UILabel = {
    let label = UILabel()
    label.text = " Title "
    //…
    label.translatesAutoresizingMaskIntoConstraints = false //Must use
    return label
}()

//…


//MARK: init
//Add Subviews and then layout Contraints to the Cell’s contentView
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    addSubViewsAndlayout()
}



/// Add and sets up subviews with programmically added constraints
func addSubViewsAndlayout() {
    contentView.addSubview(titleLabel) //will crash if not added

    let screenwidth = UIScreen.main.bounds.width //get any other properties you need

    titleLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 12.0).isActive = true
    titleLabel.heightAnchor.constraint(equalToConstant: 30).isActive = true
    titleLabel.leftAnchor.constraint(equalTo: self.contentView.leftAnchor, constant: 12).isActive = true
    titleLabel.rightAnchor.constraint(equalTo: otherViewToTheSide.rightAnchor, constant: -24).isActive = true 

//...

我也想实现以下方法,而不是使用硬编码值/字符串。

/// Get the Height of the cell
/// use this in heightForRowAt indexPath
/// - Returns: CGFloat
class func height() -> CGFloat {
    return 175
}
//CustomCell2.height()


/// Get the string identifier for this class.
///
/// - Retruns: String
class var identifier: String {
    return NSStringFromClass(self).components(separatedBy: ".").last!
}
//use when registering cell:
self.tableView.register(CustomCell2.self, forCellReuseIdentifier: CustomCell2.identifier)

答案 1 :(得分:1)

Apple's Developer Forums上的用户指出了我正确的方向。约束是在标签和单元格之间(单元格在自定义单元格的类中被称为“自我”),这里的答案是我不得不将单元格添加到单元格而不是将其添加到标签中。相同的精确约束定义,但它仅作为self.addConstraint()工作,并在编码为labelName.addConstraint()

时给出错误“视图层次结构没有为约束准备”

答案 2 :(得分:0)

您可以以编程方式创建UITableViewCell约束:

class ViewController: UITableViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.register(CustomCell2.self, forCellReuseIdentifier: "cell")
}

override func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 2
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? CustomCell2 else { return UITableViewCell() }
    cell.model = CellModel(labelString: "set constriant by code")
    return cell
}  
}

定义模型:

struct CellModel {
let labelString : String
}

定义自定义单元格:

class CustomCell2 : UITableViewCell {
private let label : UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false // enable auto-layout
    label.backgroundColor = .green // to visualize 
    label.textAlignment = .center // text alignment in center
    return label
}()

private func addLabel() {
    addSubview(label)
    NSLayoutConstraint.activate([
        // label width is 70% width of cell
        label.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.7),
        // center along horizontally 
        label.centerXAnchor.constraint(equalTo: centerXAnchor)
    ])
}

var model : CellModel? {
    didSet {
        label.text = model?.labelString ?? "Test"
    }
}

// Init 
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    addLabel()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
} 
}

Output