// // UIViewController+Children.swift // Gemini-iOS // // Created by Shadowfacts on 12/17/20. // import UIKit // Based on MVCTodo by Dave DeLong: https://github.com/davedelong/MVCTodo/blob/841649dd6aa31bacda3ad7ef9a9a836f66281e50/MVCTodo/Extensions/UIViewController.swift extension UIViewController { func embedChild(_ newChild: UIViewController, in container: UIView? = nil) { // if the view controller is already a child of something else, remove it if let oldParent = newChild.parent, oldParent != self { newChild.beginAppearanceTransition(false, animated: false) newChild.willMove(toParent: nil) newChild.removeFromParent() if newChild.viewIfLoaded?.superview != nil { newChild.viewIfLoaded?.removeFromSuperview() } newChild.endAppearanceTransition() } // since .view returns an IUO, by default the type of this is "UIView?" // explicitly type the variable because We Know Betterâ„¢ var targetContainer: UIView = container ?? self.view if !targetContainer.isContainedWithin(view) { targetContainer = view } // add the view controller as a child if newChild.parent != self { newChild.beginAppearanceTransition(true, animated: false) addChild(newChild) newChild.didMove(toParent: self) targetContainer.embedSubview(newChild.view) newChild.endAppearanceTransition() } else { // the view controller is already a child // make sure it's in the right view // we don't do the appearance transition stuff here, // because the vc is already a child, so *presumably* // that transition stuff has already appened targetContainer.embedSubview(newChild.view) } } func removeViewAndController() { view.removeFromSuperview() removeFromParent() } } // Based on MVCTodo by Dave DeLong: https://github.com/davedelong/MVCTodo/blob/841649dd6aa31bacda3ad7ef9a9a836f66281e50/MVCTodo/Extensions/UIView.swift extension UIView { func embedSubview(_ subview: UIView) { if subview.superview == self { return } if subview.superview != nil { subview.removeFromSuperview() } subview.frame = bounds addSubview(subview) NSLayoutConstraint.activate([ subview.leadingAnchor.constraint(equalTo: leadingAnchor), subview.trailingAnchor.constraint(equalTo: trailingAnchor), subview.topAnchor.constraint(equalTo: topAnchor), subview.bottomAnchor.constraint(equalTo: bottomAnchor) ]) } func isContainedWithin(_ other: UIView) -> Bool { var current: UIView? = self while let proposedView = current { if proposedView == other { return true } current = proposedView.superview } return false } }