Created
December 14, 2022 19:42
-
-
Save chunkyguy/39a8e0c2151e0b13955141544627ec46 to your computer and use it in GitHub Desktop.
UIViewController transitions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
class ContainerViewController: UIViewController { | |
private var childVwCtrl: UIViewController | |
var contentViewController: UIViewController { | |
get { childVwCtrl } | |
set { set(contentViewController: newValue, animationDuration: nil) } | |
} | |
func set(contentViewController toVwCtrl: UIViewController, animationDuration: Double?) { | |
let fromVwCtrl = childVwCtrl | |
guard let duration = animationDuration else { | |
remove(viewController: fromVwCtrl) | |
add(viewController: toVwCtrl) | |
childVwCtrl = toVwCtrl | |
return | |
} | |
addChild(toVwCtrl) | |
toVwCtrl.view.frame = contentFrame | |
fromVwCtrl.willMove(toParent: nil) | |
beginAnimation(fromView: fromVwCtrl.view, toView: toVwCtrl.view) | |
transition( | |
from: fromVwCtrl, | |
to: toVwCtrl, | |
duration: duration, | |
options: [.curveEaseOut], | |
animations: { | |
self.endAnimation( | |
fromView: fromVwCtrl.view, | |
toView: toVwCtrl.view | |
) | |
}, | |
completion: { _ in | |
toVwCtrl.didMove(toParent: self) | |
fromVwCtrl.removeFromParent() | |
self.childVwCtrl = toVwCtrl | |
} | |
) | |
} | |
private func beginAnimation(fromView: UIView, toView: UIView) { | |
fromView.transform = CGAffineTransform.identity | |
toView.transform = CGAffineTransform(translationX: 500, y: 0) | |
} | |
private func endAnimation(fromView: UIView, toView: UIView) { | |
fromView.transform = CGAffineTransform(translationX: -500, y: 0) | |
toView.transform = CGAffineTransform.identity | |
} | |
init(contentViewController: UIViewController) { | |
childVwCtrl = contentViewController | |
super.init(nibName: nil, bundle: nil) | |
add(viewController: contentViewController) | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.backgroundColor = .lightGray | |
} | |
private var contentFrame: CGRect { | |
let edge = view.bounds.size.minEdge - 100 | |
return CGRect.sized(edge).offsetBy(dx: 50, dy: 200) | |
} | |
private var contentEdgeInsets: UIEdgeInsets { | |
return UIEdgeInsets.from(outer: view.bounds, inner: contentFrame) | |
} | |
private func add(viewController: UIViewController) { | |
addChild(viewController) | |
view.addSubview(viewController.view) | |
viewController.view.frame = contentFrame | |
viewController.didMove(toParent: self) | |
} | |
private func remove(viewController: UIViewController) { | |
viewController.willMove(toParent: nil) | |
viewController.view.removeFromSuperview() | |
viewController.removeFromParent() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
class SomeViewController: UIViewController { | |
let desc: String | |
init(desc: String) { | |
self.desc = desc | |
super.init(nibName: nil, bundle: nil) | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.backgroundColor = UIColor(hue: CGFloat.random(in: 0...1), | |
saturation: 0.8, | |
brightness: 0.8, | |
alpha: 1) | |
let label = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 100, height: 80))) | |
view.addSubview(label) | |
view.addConstraints(to: label) | |
label.text = desc | |
label.font = UIFont.systemFont(ofSize: 24, weight: .bold) | |
label.textAlignment = .center | |
} | |
override var description: String { | |
return desc | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
extension CGSize { | |
var minEdge: CGFloat { min(width, height) } | |
func offset(_ val: CGFloat) -> CGSize { | |
return CGSize(width: width - val, height: height - val) | |
} | |
} | |
extension CGRect { | |
static func sized(_ value: CGFloat) -> CGRect { | |
return CGRect(origin: .zero, size: CGSize(width: value, height: value)) | |
} | |
} | |
extension UIEdgeInsets { | |
static func from(outer: CGRect, inner: CGRect) -> UIEdgeInsets { | |
return UIEdgeInsets( | |
top: inner.minY - outer.minY, | |
left: inner.minX - outer.minX, | |
bottom: outer.maxY - inner.maxY, | |
right: outer.maxX - inner.maxX) | |
} | |
static func all(_ value: CGFloat) -> UIEdgeInsets { | |
return UIEdgeInsets(top: value, left: value, bottom: value, right: value) | |
} | |
} | |
extension UIView { | |
func addConstraints(to subview: UIView, insets: UIEdgeInsets = .zero) { | |
subview.translatesAutoresizingMaskIntoConstraints = false | |
NSLayoutConstraint.activate(NSLayoutConstraint.constraints( | |
withVisualFormat: "V:|-(\(insets.top))-[vw]-(\(insets.bottom))-|", | |
metrics: nil, | |
views: ["vw": subview] | |
)) | |
NSLayoutConstraint.activate(NSLayoutConstraint.constraints( | |
withVisualFormat: "H:|-(\(insets.left))-[vw]-(\(insets.right))-|", | |
metrics: nil, | |
views: ["vw": subview] | |
)) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ViewController: UIViewController { | |
var containerVwCtrl: ContainerViewController! | |
var vwCtrls: [SomeViewController] = [] | |
var selectedIndex = 0 | |
var timer: Timer! | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
vwCtrls = (0..<5).map { SomeViewController(desc: "Child \($0)") } | |
containerVwCtrl = ContainerViewController(contentViewController: vwCtrls[selectedIndex]) | |
containerVwCtrl.modalPresentationStyle = .fullScreen | |
} | |
override func viewDidAppear(_ animated: Bool) { | |
super.viewDidAppear(animated) | |
present(containerVwCtrl, animated: false) | |
timer = Timer.scheduledTimer( | |
timeInterval: 3, | |
target: self, selector: #selector(displayNext), | |
userInfo: nil, repeats: true) | |
} | |
@objc func displayNext() { | |
selectedIndex = (selectedIndex + 1) % vwCtrls.count | |
containerVwCtrl.set(contentViewController: vwCtrls[selectedIndex], animationDuration: 1) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment