swiftdynamicheightuicontainerviewchildviewcontroller

How to adjust height of child view controller to match container view's height


I have a container View with adjustable height. Now I want to set the same frame of the view of child view controller according to container view's height. Sometimes it does work in the simulation but often it fails. The frame of child view controller's view often stays the same as defined at the beginning. Do you know a workaround to solve this problem ?

Here is my main ViewController with containerView named bottomView

class ViewController: UIViewController {
    var startPosition: CGPoint!
    var originalHeight: CGFloat = 0
    var bottomView = UIView()
    var gestureRecognizer = UIPanGestureRecognizer()
    let scrollView = UIScrollView()
    let controller = EditorViewController()

    override func viewDidLoad() {
        self.view.backgroundColor = .white 
        view.addSubview(bottomView)
        bottomView.translatesAutoresizingMaskIntoConstraints = false
        bottomView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        bottomView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        bottomView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        bottomView.heightAnchor.constraint(equalToConstant: 100).isActive = true
        bottomView.backgroundColor = .white

        gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(viewDidDragged(_:)))
        bottomView.isUserInteractionEnabled = true
        bottomView.addGestureRecognizer(gestureRecognizer)

        // add childviewController

        self.addChild(controller)
        controller.view.translatesAutoresizingMaskIntoConstraints = false
        controller.view.frame = bottomView.bounds
        bottomView.addSubview(controller.view)        
        controller.view.rightAnchor.constraint(equalTo: bottomView.rightAnchor).isActive = true
        controller.view.leftAnchor.constraint(equalTo: bottomView.leftAnchor).isActive = true
        controller.view.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor).isActive = true
        controller.view.topAnchor.constraint(equalTo: bottomView.topAnchor).isActive = true
        controller.didMove(toParent: self)

    }
}

The childView Controller looks like this:

class EditorViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .red   
    }

And in this way I change the height of container view and tried to adjust the height of child viewController, too. But it does not work.

@objc func viewDidDragged(_ sender: UIPanGestureRecognizer) {

        if sender.state == .began {
            startPosition = gestureRecognizer.location(in: self.view) // the postion at which PanGestue Started
            originalHeight = bottomView.frame.size.height
        }
        if sender.state == .began || sender.state == .changed {
            let endPosition = sender.location(in: self.view)
            let difference = endPosition.y  - startPosition.y
            let newHeight = originalHeight - difference
            if self.view.frame.size.height - endPosition.y < 100 {
                bottomView.frame = CGRect(x: 0, y: self.view.frame.size.height - 100, width: self.view.frame.size.width, height: 100)
                controller.view.frame = bottomView.bounds  
            } else {
                bottomView.frame = CGRect(x: 0, y: self.view.frame.size.height - newHeight, width: self.view.frame.size.width, height: newHeight)
                controller.view.frame = bottomView.bounds
            }
        }

        if sender.state == .ended || sender.state == .cancelled {
            //Do Something
        }
    }

Solution

  • Try using a constraint to change the height. Something like:

    class ViewController: UIViewController {
      ...
    
      var heightConstraint: NSLayoutConstraint?
    
      override func viewDidLoad() {
    
        ...
    
        heightConstraint = bottomView.heightAnchor.constraint(equalToConstant: 100)
        heightConstraint?.isActive = true
    
        ....
    
      }
    
      @objc func viewDidDragged(_ sender: UIPanGestureRecognizer) {
    
        ...
    
        if sender.state == .began || sender.state == .changed {
          let endPosition = sender.location(in: self.view)
          let difference = endPosition.y  - startPosition.y
          let newHeight = originalHeight - difference
          if self.view.frame.size.height - endPosition.y < 100 {
            heightConstraint?.constant = 100
          } else {
            heightConstraint?.constant = newHeight
          }
        }
    
        ...
    
      }
    }