Search code examples
iosswift

Swift: child view controller content size


I have parent view controller and child view controller. I use button to show child view controller. Before to show child view I need to enter x, y position and enter width and size of child view. I want to enter x, y position in parent view controller and get real width and height size from child view controller. How to do it?

I tried to do this

child.view.translatesAutoresizingMaskIntoConstraints = false

I can get real child size using this line, but in this case my x and y positions = 0 and I can't fix it.

parent:

func action() {
     let child = ChildVC()
     addChildViewController(child)
     view.addSubview(child.view)
     child.didMove(toParentViewController: self)
        
     child.view.frame = CGRect(
          x: button.frame.origin.x,
          y: button.frame.origin.y,
          width: ?,
          height: ? )
}

child:

var titleLabel: UILabel = {
    let label = UILabel()
    label.text = "title"
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
}()

var imageView: UIImageView = {
    let imageView = UIImageView()
    imageView.image = UIImage(named: "iOS2")
    imageView.translatesAutoresizingMaskIntoConstraints = false
    return imageView
}()

let backgroundView: UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

private lazy var menu: UIStackView = {
    let stackView = UIStackView()
    stackView.axis = .vertical
    stackView.spacing = 0
    stackView.distribution = .fillProportionally
    stackView.translatesAutoresizingMaskIntoConstraints = false
    return stackView
}()

private lazy var section: UIStackView = {
    let stackView = UIStackView()
    stackView.axis = .vertical
    stackView.spacing = 16
    stackView.alignment = .center
    stackView.distribution = .fillProportionally
    stackView.translatesAutoresizingMaskIntoConstraints = false
    return stackView
}()

private lazy var cell: UIStackView = {
    let stackView = UIStackView()
    stackView.axis = .horizontal
    stackView.spacing = 16
    stackView.alignment = .fill
    stackView.distribution = .equalSpacing
    stackView.translatesAutoresizingMaskIntoConstraints = false
    return stackView
}()

let sectionNumber = 3

override func viewDidLoad() {
    super.viewDidLoad()

    setupView()
    setupConstraints()
    setupMenu()
}

func setupView() {
    view.addSubview(backgroundView)
    view.addSubview(menu)
}

func setupConstraints() {
    
    backgroundView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0.0).isActive = true
    backgroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0.0).isActive = true
    backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0).isActive = true
    backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0.0).isActive = true
    
    menu.topAnchor.constraint(equalTo: backgroundView.topAnchor, constant: 0.0).isActive = true
    menu.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor, constant: 0.0).isActive = true
    menu.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor, constant: 0.0).isActive = true
    menu.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor, constant: 0.0).isActive = true
}

func setupMenu() {
    
    for index in 0...sectionNumber {
        
        section = UIStackView()
        section.tag = index
        menu.addArrangedSubview(section)
        
        cell = UIStackView()
        cell.tag = index
        section.addArrangedSubview(cell)
        
        titleLabel = UILabel()
        imageView = UIImageView()
        
        cell.addArrangedSubview(titleLabel)
        cell.addArrangedSubview(imageView)
        cell.addSubview(button)
        
        if cell.tag == 0 {
            titleLabel.text = "text text text text"
            imageView.image = UIImage(named: "iOS2")
        } else if cell.tag == 1 {
            titleLabel.text = "text text text"
            imageView.image = UIImage(named: "iOS3")
        } else if cell.tag == 2 {
            titleLabel.text = "text"
            imageView.image = UIImage(named: "iOS1")
        }else {
            titleLabel.text = "text text"
            imageView.image = UIImage(named: "iOS2")
        }
    }
    
}

Solution

  • We can tell the child controller's view to use autolayout...

    Your posted action() func:

    func action() {
         let child = ChildVC()
         addChildViewController(child)
         view.addSubview(child.view)
         child.didMove(toParentViewController: self)
            
         child.view.frame = CGRect(
              x: button.frame.origin.x,
              y: button.frame.origin.y,
              width: ?,
              height: ? )
    }
    

    doesn't indicate where button is being set, but let's assume you have done so.

    Change the function to this:

    func action() {
        
        let child = SomeChildVC()
        addChild(child)
        
        // unwrap optional .view
        guard let childView = child.view else { fatalError("Child VC has no view!!!") }
        view.addSubview(childView)
        child.didMove(toParent: self)
        
        childView.translatesAutoresizingMaskIntoConstraints = false
        childView.topAnchor.constraint(equalTo: button.topAnchor).isActive = true
        childView.leadingAnchor.constraint(equalTo: button.leadingAnchor).isActive = true
        
    }
    

    Now, the child controller's .view will be placed at the top-left corner of button, and its layout constraints will determine its width and height.