skip to Main Content

Error:-

Thread 1: "Unable to activate constraint with anchors <NSLayoutXAxisAnchor:0x280af8500 "UILabel:0x103dc4fa0.centerX"> and <NSLayoutXAxisAnchor:0x280af89c0 "UIView:0x103dc49d0.centerX"> because they have no common ancestor.  Does the constraint or its anchors reference items in different view hierarchies?  That's illegal."

I’ve created a function programmatical in Base view controller which returns a view & I’ve added some constraints to its

Function:-

func getMarker (lbl:String, img:UIImage) -> UIView {
        let myView = UIView(frame: CGRect.zero)
        myView.center = CGPoint(x: 50, y: 160)
        myView.backgroundColor = UIColor.clear


        let imageView = UIImageView(image: img)
        imageView.frame = CGRect(x: 0, y: 0, width: 20, height: 40)
        myView.addSubview(imageView)


        let label = UILabel(frame: CGRect(x: 0, y: 45, width: 120, height: 30))
        label.text = lbl
        label.textAlignment = .center
        label.adjustsFontSizeToFitWidth = true
        label.textColor = UIColor.black
        label.backgroundColor = UIColor.white
        label.layer.borderColor = UIColor.lightGray.cgColor
        label.layer.borderWidth = 0.5
        label.layer.cornerRadius = 5
        label.layer.masksToBounds = true
        label.sizeToFit()

        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
            imageView.centerXAnchor.constraint(equalTo: myView.centerXAnchor)
        ])

        myView.addSubview(label)

        return myView
    }

calling function in another controller but it crashing and showing me the error which I mentioned above

Calling function:-

getMarker(lbl: device.name ?? "", img: (UIImage(named: icfile) ?? UIImage(named: "truck_1_orange")!))

2

Answers


  1. U need to add subview first, then activate layout. Label is not in myView subviews in your code. It is not in any hierarchy at the moment of layout constraint activation.

    myView.addSubview(label)    
    NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
            imageView.centerXAnchor.constraint(equalTo: myView.centerXAnchor)
        ])
        
    
    Login or Signup to reply.
  2. You need to configure the layout of your subviews (imageView and label) in order to have them sized and positioned where you want them.

    Take a look at this example code:

    class MarkerVC: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            view.backgroundColor = .systemBlue
            
            guard let img = UIImage(named: "img80x80")
            else {
                fatalError("Could not load sample image!!!")
            }
    
            let markerView1 = getMarker(lbl: "Testing", img: img)
            
            let markerView2 = getMarkerAutoSized(lbl: "Testing", img: img)
    
            markerView1.translatesAutoresizingMaskIntoConstraints = false
            markerView2.translatesAutoresizingMaskIntoConstraints = false
    
            view.addSubview(markerView1)
            view.addSubview(markerView2)
    
            // respect safe area
            let safeG = view.safeAreaLayoutGuide
            
            NSLayoutConstraint.activate([
                
                // we have to set both Position and Size constraints
                //  for markerView1
                markerView1.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 20.0),
                markerView1.widthAnchor.constraint(equalToConstant: 240.0),
                markerView1.heightAnchor.constraint(equalToConstant: 100.0),
                markerView1.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                
                // markerView2 uses its subviews to set its own size
                //  so we only need position constraints
                markerView2.topAnchor.constraint(equalTo: markerView1.bottomAnchor, constant: 20.0),
                markerView2.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                
            ])
    
            // so we can see the view frames
            markerView1.backgroundColor = .systemRed
            markerView2.backgroundColor = .systemRed
    
        }
        
        func getMarker (lbl:String, img:UIImage) -> UIView {
            
            let myView = UIView()
            myView.backgroundColor = UIColor.clear
            
            let imageView = UIImageView(image: img)
    
            let label = UILabel()
            label.text = lbl
            label.textAlignment = .center
            label.adjustsFontSizeToFitWidth = true
            label.textColor = UIColor.black
            label.backgroundColor = UIColor.white
            label.layer.borderColor = UIColor.lightGray.cgColor
            label.layer.borderWidth = 0.5
            label.layer.cornerRadius = 5
            label.layer.masksToBounds = true
    
            imageView.translatesAutoresizingMaskIntoConstraints = false
            label.translatesAutoresizingMaskIntoConstraints = false
            
            myView.addSubview(imageView)
            myView.addSubview(label)
    
            NSLayoutConstraint.activate([
    
                // image view Width and Height
                imageView.widthAnchor.constraint(equalToConstant: 20.0),
                imageView.heightAnchor.constraint(equalToConstant: 40.0),
    
                // labe Width and Height
                label.widthAnchor.constraint(equalToConstant: 120.0),
                label.heightAnchor.constraint(equalToConstant: 30.0),
                
                // image view aligned to Top
                imageView.topAnchor.constraint(equalTo: myView.topAnchor),
                // centered Horizontally
                imageView.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
                
                // label 5-pts below image view
                label.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 5.0),
                // centered Horizontally
                label.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
                
            ])
            
            return myView
        }
        
        func getMarkerAutoSized (lbl:String, img:UIImage) -> UIView {
            
            let myView = UIView()
            myView.backgroundColor = UIColor.clear
            
            let imageView = UIImageView(image: img)
            
            let label = UILabel()
            label.text = lbl
            label.textAlignment = .center
            label.adjustsFontSizeToFitWidth = true
            label.textColor = UIColor.black
            label.backgroundColor = UIColor.white
            label.layer.borderColor = UIColor.lightGray.cgColor
            label.layer.borderWidth = 0.5
            label.layer.cornerRadius = 5
            label.layer.masksToBounds = true
            
            imageView.translatesAutoresizingMaskIntoConstraints = false
            label.translatesAutoresizingMaskIntoConstraints = false
            
            myView.addSubview(imageView)
            myView.addSubview(label)
            
            NSLayoutConstraint.activate([
                
                // image view Width and Height
                imageView.widthAnchor.constraint(equalToConstant: 20.0),
                imageView.heightAnchor.constraint(equalToConstant: 40.0),
                
                // labe Width and Height
                label.widthAnchor.constraint(equalToConstant: 120.0),
                label.heightAnchor.constraint(equalToConstant: 30.0),
                
                // image view aligned to Top
                imageView.topAnchor.constraint(equalTo: myView.topAnchor),
                // centered Horizontally
                imageView.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
                
                // label 5-pts below image view
                label.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 5.0),
                // centered Horizontally
                label.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
                
                // to auto-size myView
                label.leadingAnchor.constraint(equalTo: myView.leadingAnchor),
                label.trailingAnchor.constraint(equalTo: myView.trailingAnchor),
                label.bottomAnchor.constraint(equalTo: myView.bottomAnchor),
                
            ])
            
            return myView
        }
        
    }
    

    I modified your getMarker(...) func to size and position the subviews.

    I also added a very similar getMarkerAutoSized(...) func that uses a couple additional constraints on the subviews.

    For the first version, we must set both the Position and Size of the generated view.

    For the second version, we only need to set the generated view’s Position because it sizes itself to fit its subviews.

    Here’s how they look:

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search