I have a set of AL constraints positioning a child vc that has two positions, expanded and collapsed.
I found that when I add the collapsed constraint, a top anchor to bottom anchor constraint with a constant, when the vc is first created, there seems to be additional spacing when I activate it. Seemingly because the actual height isn't available at the time.
When I add the constraint in viewDidLayoutSubviews there additional spacing is gone and the constraint behaves properly. Except the issue that now when I switch between the constraints in an animation, I cannot deactivate the collapsed constraint as I switch to the expanded constraint and the constraint breaks. Possibly because viewDidLayoutSubviews is called throughout the transition animation.
Here's an abstract of vc setup.
var foregroundExpandedConstraint: NSLayoutConstraint!
var foregroundCollapsedConstraint: NSLayoutConstraint!
var foregroundViewController: UIViewController? {
    didSet {
        setupforegroundViewController(foregroundViewController: foregroundViewController!)
    }
}
func setupforegroundViewController(foregroundViewController: UIViewController) {
    addChildViewController(foregroundViewController)
    foregroundViewController.didMove(toParentViewController: self)
    guard let foregroundView = foregroundViewController.view else { return }
    foregroundView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(foregroundView)
    foregroundExpandedConstraint = foregroundView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 15)
    let height =  view.safeAreaLayoutGuide.layoutFrame.height - 50 - 15
    let cellHeight = ((height) / 6)        
    foregroundCollapsedConstraint = NSLayoutConstraint(item: foregroundView, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: (-cellHeight) * 2 - 50)
    let foregroundViewControllerViewConstraints = [
        foregroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        foregroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
        foregroundView.heightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.heightAnchor, constant: -50 - 15),
        foregroundExpandedConstraint!
        ]
    NSLayoutConstraint.activate(foregroundViewControllerViewConstraints)
}
And here the animations are preformed using UIViewPropertyAnimator.
func animateTransitionIfNeeded(state: ForegroundState, duration: TimeInterval) {
    let containerFrameAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1) {
        [unowned self] in
        switch state {
        case .expanded:
            self.foregroundCollapsedConstraint?.isActive = false
            self.foregroundExpandedConstraint?.isActive = true
            self.view.layoutIfNeeded()
        case .collapsed:
            self.foregroundExpandedConstraint?.isActive = false
            self.foregroundCollapsedConstraint?.isActive = true
            self.view.layoutIfNeeded()
        }
    }
    containerFrameAnimator.addCompletion {  [weak self] (position) in
        if position == .start {
            switch state {
            case .collapsed:
                self?.foregroundCollapsedConstraint?.isActive = false
                self?.foregroundExpandedConstraint?.isActive = true
                self?.foregroundIsExpanded = true
                self?.view.layoutIfNeeded()
            case .expanded:
                self?.foregroundExpandedConstraint?.isActive = false
                self?.foregroundCollapsedConstraint?.isActive = true
                self?.foregroundIsExpanded = false
                self?.view.layoutIfNeeded()
            }
        } else if position == .end {
            switch state {
            case .collapsed:
                self?.foregroundExpandedConstraint?.isActive = false
                self?.foregroundCollapsedConstraint?.isActive = true
                self?.foregroundIsExpanded = false
            case .expanded:
                self?.foregroundExpandedConstraint?.isActive = false
                self?.foregroundCollapsedConstraint?.isActive = true
                self?.foregroundIsExpanded = true
            }
        }
        self?.runningAnimations.removeAll()
    }
Again to reiterate, when I use the following code, setting the constraint as the vc is added to the view hierarchy, it doesn't layout properly. Checking the constraints I see they change after view did layout subviews is called. Each constraint changes appropriately except for the collapsed constraint.
When I add the collapsed constraint in view did layout subviews it behaves properly however I am unable to deactivate it going forwards and the constraint breaks.
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let height =  view.safeAreaLayoutGuide.layoutFrame.height - 50 - 15
    let cellHeight = ((height) / 6)
    if let v = foregroundViewController?.view {
        foregroundCollapsedConstraint = NSLayoutConstraint(item: v, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: (-cellHeight) * 2 - 50)
    }
}
Edit: I've created a repo demonstrating the issue: https://github.com/louiss98/UIViewPropertyAnimator-Layout-Test
Any suggestions?
 
    