87 lines
3.0 KiB
Swift
87 lines
3.0 KiB
Swift
|
//
|
||
|
// 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
|
||
|
}
|
||
|
}
|
||
|
|