Search code examples
iosswiftnslayoutconstraintjtapplecalendarnslayoutanchor

Unable to activate constraint with anchors.... because they have no common ancestor


I am attempting to create a Swift-based UI programmatically that resembles the layout shown below

enter image description here

Below is my view hierarchy which I created using xib. Now I'm attempting to achieve the same through programatically.

here

Below is the code which i'm attempting. Here JTACDayCell is the child of UICollectionViewCell

FYI: JTACDayCell belongs to JTAppleCalendar library

class DateTableCell: JTACDayCell {
static let reuseID = "dateCell"
lazy var parentView: UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

lazy var selectedView: UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

lazy var dateLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
}()

lazy var eventView: UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

lazy var separatorView: UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = .lightGray
    return view
}()

override init(frame: CGRect) {
    super.init(frame: frame)
    setUpAutoLayout()
    
    parentView.addSubview(selectedView)
    parentView.addSubview(dateLabel)
    parentView.addSubview(eventView)
    
    addSubview(parentView)
    addSubview(separatorView)
}

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

private func setUpAutoLayout() {
    NSLayoutConstraint.activate([
        parentView.leftAnchor.constraint(equalTo: leftAnchor),
        parentView.rightAnchor.constraint(equalTo: rightAnchor),
        parentView.topAnchor.constraint(equalTo: topAnchor),
        parentView.bottomAnchor.constraint(equalTo: separatorView.topAnchor),
        
        selectedView.centerXAnchor.constraint(equalTo: parentView.centerXAnchor),
        selectedView.centerYAnchor.constraint(equalTo: parentView.centerYAnchor, constant: -2.5),
        selectedView.widthAnchor.constraint(equalToConstant: 35),
        selectedView.heightAnchor.constraint(equalToConstant: 35),
        
        dateLabel.centerXAnchor.constraint(equalTo: parentView.centerXAnchor),
        dateLabel.centerYAnchor.constraint(equalTo: parentView.centerYAnchor, constant: -2.5),
        
        eventView.centerXAnchor.constraint(equalTo: parentView.centerXAnchor),
        eventView.widthAnchor.constraint(equalToConstant: 6),
        eventView.heightAnchor.constraint(equalToConstant: 6),
        eventView.bottomAnchor.constraint(equalTo: parentView.topAnchor, constant: 5),
        
        separatorView.leftAnchor.constraint(equalTo: leftAnchor),
        separatorView.rightAnchor.constraint(equalTo: rightAnchor),
        separatorView.heightAnchor.constraint(equalToConstant: 0.5),
        separatorView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 1)
    ])
}
}

Upon executing the provided code, I encounter the following error

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors <NSLayoutXAxisAnchor:0x6000034619c0 "UIView:0x7fb1a8a20ce0.left"> and <NSLayoutXAxisAnchor:0x600003460800 "AppName.DateTableCell:0x7fb1a8a28470.left"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.'

What might be the issue here?


Solution

  • Call your setUpAutoLayout() function after added subviews

    override init(frame: CGRect) {
        super.init(frame: frame)
        
        
        parentView.addSubview(selectedView)
        parentView.addSubview(dateLabel)
        parentView.addSubview(eventView)
        
        addSubview(parentView)
        addSubview(separatorView)
    
        setUpAutoLayout()
    }