Skip to content

Commit b3044c6

Browse files
authored
Add support for user's snapFrames for IBPreviewFreeForm (#17)
* Add CallCodeTracker, to test possibility of separation of IBPreviews to external repository * Fix exact commit definition * IBPreviewRepresentable are available always and are unified for view and view controller * Delete built-in snapFrames. It's up to the user to define it's snapFrames This eliminates the need to list always correct frames of supported devices by Apple
1 parent 03d6156 commit b3044c6

File tree

5 files changed

+111
-52
lines changed

5 files changed

+111
-52
lines changed

Package.resolved

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,11 @@ let package = Package(
1111
products: [
1212
.library(name: "UIViewKit", targets: ["UIViewKit"])
1313
],
14+
dependencies: [
15+
.package(url: "https://github.com/Adobels/CodeCallTracker.git", revision: "1d27da6706466a5b83bdb0f4097fc86f678b146f")
16+
],
1417
targets: [
15-
.target(
16-
name: "UIViewKit"
17-
),
18-
.testTarget(
19-
name: "UIViewKitTests",
20-
dependencies: [
21-
"UIViewKit"
22-
])
18+
.target(name: "UIViewKit", dependencies: ["CodeCallTracker"]),
19+
.testTarget(name: "UIViewKitTests", dependencies: ["UIViewKit"])
2320
]
2421
)

Sources/UIViewKit/IBPreviews/IBPreviewFreeForm.swift

Lines changed: 74 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,31 +18,61 @@ public class IBPreviewFreeForm: ViewControllerFreeFormContainer {
1818
fatalError()
1919
}
2020

21+
public init(snapFrames: SnapFrame..., view: UIView) {
22+
super.init(snapFrames: snapFrames)
23+
self.viewMaker = { view }
24+
}
25+
2126
public init(view: UIView) {
2227
super.init(nibName: nil, bundle: nil)
2328
self.viewMaker = { view }
2429
}
2530

31+
public init(snapFrames: SnapFrame..., viewMaker: @escaping () -> UIView) {
32+
super.init(snapFrames: snapFrames)
33+
self.viewMaker = viewMaker
34+
}
35+
2636
public init(_ viewMaker: @escaping () -> UIView) {
2737
super.init(nibName: nil, bundle: nil)
2838
self.viewMaker = viewMaker
2939
}
3040

41+
public init(snapFrames: SnapFrame..., viewController: UIViewController) {
42+
super.init(snapFrames: snapFrames)
43+
self.viewControllerMaker = { viewController }
44+
}
45+
3146
public init(viewController: UIViewController) {
3247
super.init(nibName: nil, bundle: nil)
3348
self.viewControllerMaker = { viewController }
3449
}
3550

51+
public init(snapFrames: SnapFrame..., viewControllerMaker: @escaping () -> UIViewController) {
52+
super.init(snapFrames: snapFrames)
53+
self.viewControllerMaker = viewControllerMaker
54+
}
55+
3656
public init(_ viewControllerMaker: @escaping () -> UIViewController) {
3757
super.init(nibName: nil, bundle: nil)
3858
self.viewControllerMaker = viewControllerMaker
3959
}
4060

61+
public init(snapFrames: SnapFrame..., view: some View) {
62+
super.init(snapFrames: snapFrames)
63+
self.viewControllerMaker = { UIHostingController(rootView: view) }
64+
}
65+
4166
public init(view: some View) {
4267
super.init(nibName: nil, bundle: nil)
4368
self.viewControllerMaker = { UIHostingController(rootView: view) }
4469
}
4570

71+
public init(snapFrames: SnapFrame..., viewMaker: @escaping () -> some View) {
72+
super.init(snapFrames: snapFrames )
73+
self.viewControllerMaker = { UIHostingController(rootView: viewMaker()) }
74+
}
75+
4676
public init(_ viewMaker: @escaping () -> some View) {
4777
super.init(nibName: nil, bundle: nil)
4878
self.viewControllerMaker = { UIHostingController(rootView: viewMaker()) }
@@ -75,52 +105,60 @@ public class IBPreviewFreeForm: ViewControllerFreeFormContainer {
75105

76106
}
77107

108+
extension IBPreviewFreeForm {
109+
110+
public protocol SnapFrame {
111+
var size: CGSize { get }
112+
var name: String { get }
113+
var color: UIColor { get }
114+
var borderWidth: CGFloat { get }
115+
}
116+
117+
}
118+
78119
public class ViewControllerFreeFormContainer: UIViewController {
79120

121+
var snapFrames: [IBPreviewFreeForm.SnapFrame] = []
122+
var deviceWiteframesViews: [UIView] = []
80123
var containerView: UIView!
81124
var heightConstraint: NSLayoutConstraint!
82125
var widthConstraint: NSLayoutConstraint!
83-
private var iPhoneSE2FrameView: UIView!
84-
private var iPhoneSE2WithKeyboardFrameView: UIView!
85126
private var snapToViewFeature: SnapToViewFeature!
86-
private let iPhoneSE2Frame = CGRect(origin: .zero, size: .init(width: 375, height: 667))
87-
private let iPhoneSE2WithKeyboardFrame = CGRect(origin: .zero, size: .init(width: 375, height: 451))
127+
128+
required init?(coder: NSCoder) {
129+
fatalError("init(coder:) has not been implemented")
130+
}
131+
132+
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
133+
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
134+
}
135+
136+
init(snapFrames: [IBPreviewFreeForm.SnapFrame]) {
137+
self.snapFrames = snapFrames
138+
super.init(nibName: nil, bundle: nil)
139+
}
88140

89141
public override func loadView() {
90142
super.loadView()
91143
view.backgroundColor = .lightGray
92-
view.ibSubviews { superview in
93-
UIView().ibOutlet(&iPhoneSE2FrameView).ibSubviews { superview in
94-
UILabel().ibAttributes {
95-
$0.ibConstraints(to: superview, guide: .view, anchors: .left, .bottom, .right)
96-
$0.text = "iPhone SE2"
97-
$0.textAlignment = .center
98-
$0.textColor = .cyan
144+
snapFrames.forEach { deviceWireframe in
145+
view.ibSubviews {
146+
UIView().ibSubviews { labelSuperview in
147+
UILabel().ibAttributes {
148+
$0.ibConstraints(to: labelSuperview, guide: .view, anchors: .left, .bottom, .right)
149+
$0.text = deviceWireframe.name
150+
$0.textAlignment = .center
151+
$0.textColor = deviceWireframe.color
152+
}
153+
}.ibAttributes {
154+
$0.topAnchor.constraint(equalTo: view.topAnchor)
155+
$0.leadingAnchor.constraint(equalTo: view.leadingAnchor)
156+
$0.widthAnchor.constraint(equalToConstant: deviceWireframe.size.width)
157+
$0.heightAnchor.constraint(equalToConstant: deviceWireframe.size.height)
158+
$0.layer.borderColor = deviceWireframe.color.cgColor
159+
$0.layer.borderWidth = 2
160+
deviceWiteframesViews.append($0)
99161
}
100-
}.ibAttributes {
101-
$0.topAnchor.constraint(equalTo: superview.topAnchor)
102-
$0.leadingAnchor.constraint(equalTo: superview.leadingAnchor)
103-
$0.widthAnchor.constraint(equalToConstant: iPhoneSE2Frame.width)
104-
$0.heightAnchor.constraint(equalToConstant: iPhoneSE2Frame.height)
105-
$0.layer.borderColor = UIColor.cyan.cgColor
106-
$0.layer.borderWidth = 2
107-
}
108-
}
109-
view.ibSubviews { superview in
110-
UIView().ibOutlet(&iPhoneSE2WithKeyboardFrameView).ibSubviews { superview in
111-
UILabel().ibAttributes {
112-
$0.ibConstraints(to: superview, guide: .view, anchors: .left, .bottom, .right)
113-
$0.text = "iPhone SE2 With Keyboard"
114-
$0.textAlignment = .center
115-
$0.textColor = UIColor.yellow
116-
}
117-
}.ibAttributes {
118-
$0.topAnchor.constraint(equalTo: superview.topAnchor)
119-
$0.leadingAnchor.constraint(equalTo: superview.leadingAnchor)
120-
$0.widthAnchor.constraint(equalToConstant: iPhoneSE2WithKeyboardFrame.width)
121-
$0.heightAnchor.constraint(equalToConstant: iPhoneSE2WithKeyboardFrame.height)
122-
$0.layer.borderColor = UIColor.yellow.cgColor
123-
$0.layer.borderWidth = 2
124162
}
125163
}
126164
view.ibSubviews { superview in
@@ -132,11 +170,7 @@ public class ViewControllerFreeFormContainer: UIViewController {
132170
}
133171
}
134172
snapToViewFeature = .init(
135-
viewToSnap: [
136-
iPhoneSE2WithKeyboardFrameView,
137-
iPhoneSE2FrameView,
138-
view,
139-
],
173+
viewToSnap: deviceWiteframesViews + [view],
140174
containerView: containerView,
141175
controller: self
142176
)

Sources/UIViewKit/IBPreviews/IBRepresentables.swift

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,22 @@
88
import UIKit
99
import SwiftUI
1010

11-
@available(iOS, introduced: 13, obsoleted: 17)
12-
public struct IBRepresentableViewController: UIViewControllerRepresentable {
11+
public func IBPreviewRepresentable(view: UIView) -> some UIViewRepresentable {
12+
IBRepresentableView(view)
13+
}
14+
15+
public func IBPreviewRepresentable(_ viewMaker: @escaping () -> UIView) -> some UIViewRepresentable {
16+
IBRepresentableView(viewMaker)
17+
}
18+
public func IBPreviewRepresentable(viewController: UIViewController) -> some UIViewControllerRepresentable {
19+
IBRepresentableViewController(viewController)
20+
}
21+
22+
public func IBPreviewRepresentable(_ viewControllerMaker: @escaping () -> UIViewController) -> some UIViewControllerRepresentable {
23+
IBRepresentableViewController(viewControllerMaker)
24+
}
25+
26+
private struct IBRepresentableViewController: UIViewControllerRepresentable {
1327

1428
public typealias UIViewControllerType = UIViewController
1529

@@ -30,8 +44,7 @@ public struct IBRepresentableViewController: UIViewControllerRepresentable {
3044
public func updateUIViewController(_ uiViewController: UIViewController, context: Context) { }
3145
}
3246

33-
@available(iOS, introduced: 13, obsoleted: 17)
34-
public struct IBRepresentableView: UIViewRepresentable {
47+
private struct IBRepresentableView: UIViewRepresentable {
3548

3649
public typealias UIViewType = UIView
3750

Sources/UIViewKit/UIViewKit.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010

1111
@_exported import UIKit
1212
@_exported import SwiftUI
13+
@_exported import CodeCallTracker

0 commit comments

Comments
 (0)