-
Notifications
You must be signed in to change notification settings - Fork 682
/
Copy pathUIViewController+AddBehaviors.swift
134 lines (105 loc) · 4.55 KB
/
UIViewController+AddBehaviors.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//
// UIViewController+addBehaviors.swift
// ExampleMVVM
//
// Created by Oleh Kudinov on 03/04/2020.
//
// View controller lifecycle behaviors https://irace.me/lifecycle-behaviors
// Behaviors are very useful to reuse logic for cases like Keyboard Behaviour.
// Where ViewController on didLoad adds behaviour which observes keyboard frame
// and scrollView content inset changes based on keyboard frame.
import UIKit
protocol ViewControllerLifecycleBehavior {
func viewDidLoad(viewController: UIViewController)
func viewWillAppear(viewController: UIViewController)
func viewDidAppear(viewController: UIViewController)
func viewWillDisappear(viewController: UIViewController)
func viewDidDisappear(viewController: UIViewController)
func viewWillLayoutSubviews(viewController: UIViewController)
func viewDidLayoutSubviews(viewController: UIViewController)
}
// Default implementations
extension ViewControllerLifecycleBehavior {
func viewDidLoad(viewController: UIViewController) {}
func viewWillAppear(viewController: UIViewController) {}
func viewDidAppear(viewController: UIViewController) {}
func viewWillDisappear(viewController: UIViewController) {}
func viewDidDisappear(viewController: UIViewController) {}
func viewWillLayoutSubviews(viewController: UIViewController) {}
func viewDidLayoutSubviews(viewController: UIViewController) {}
}
extension UIViewController {
/*
Add behaviors to be hooked into this view controller’s lifecycle.
This method requires the view controller’s view to be loaded, so it’s best to call
in `viewDidLoad` to avoid it being loaded prematurely.
- parameter behaviors: Behaviors to be added.
*/
func addBehaviors(_ behaviors: [ViewControllerLifecycleBehavior]) {
let behaviorViewController = LifecycleBehaviorViewController(behaviors: behaviors)
addChild(behaviorViewController)
view.addSubview(behaviorViewController.view)
behaviorViewController.didMove(toParent: self)
}
private final class LifecycleBehaviorViewController: UIViewController, UIGestureRecognizerDelegate {
private let behaviors: [ViewControllerLifecycleBehavior]
// MARK: - Lifecicle
init(behaviors: [ViewControllerLifecycleBehavior]) {
self.behaviors = behaviors
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.isHidden = true
applyBehaviors { behavior, viewController in
behavior.viewDidLoad(viewController: viewController)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
applyBehaviors { behavior, viewController in
behavior.viewWillAppear(viewController: viewController)
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
applyBehaviors { behavior, viewController in
behavior.viewDidAppear(viewController: viewController)
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
applyBehaviors { behavior, viewController in
behavior.viewWillDisappear(viewController: viewController)
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
applyBehaviors { behavior, viewController in
behavior.viewDidDisappear(viewController: viewController)
}
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
applyBehaviors { behavior, viewController in
behavior.viewWillLayoutSubviews(viewController: viewController)
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
applyBehaviors { behavior, viewController in
behavior.viewDidLayoutSubviews(viewController: viewController)
}
}
// MARK: - Private
private func applyBehaviors(body: (_ behavior: ViewControllerLifecycleBehavior, _ viewController: UIViewController) -> Void) {
guard let parent = parent else { return }
for behavior in behaviors {
body(behavior, parent)
}
}
}
}