@@ -11,104 +11,43 @@ import SwiftUI
1111
1212/// A container for UIKit `UIView` elements. Conforms to the `UIViewRepresentable` protocol to allow conversion into SwiftUI `View`s.
1313@available ( iOS 13 . 0 , * )
14- public struct UIViewContainer < Child: UIView > : Identifiable {
15-
16- public var id : UIView { view }
14+ public struct UIViewContainer < Child: UIView > {
1715
18- /// The type of Layout to apply to the SwiftUI `View`.
19- public enum Layout {
16+ let viewCreator : ( ) -> Child
17+ let layout : Layout
2018
21- /// Uses the size returned by .`systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)`.
22- case intrinsic
23-
24- /// Uses an intrinsic height combined with a fixed width.
25- case fixedWidth( width: CGFloat )
26-
27- /// A fixed width and height is used.
28- case fixed( size: CGSize )
29- }
30-
31- private let view : Child
32- private let layout : Layout
33-
34- /// - Returns: The `CGSize` to apply to the view.
35- private var size : CGSize {
36- switch layout {
37- case . fixedWidth( let width) :
38- // Set the frame of the cell, so that the layout can be updated.
39- var newFrame = view. frame
40- newFrame. size = CGSize ( width: width, height: UIView . layoutFittingExpandedSize. height)
41- view. frame = newFrame
42-
43- // Make sure the contents of the cell have the correct layout.
44- view. setNeedsLayout ( )
45- view. layoutIfNeeded ( )
46-
47- // Get the size of the cell
48- let computedSize = view. systemLayoutSizeFitting ( UIView . layoutFittingCompressedSize)
49-
50- // Apple: "Only consider the height for cells, because the contentView isn't anchored correctly sometimes." We use ceil to make sure we get rounded numbers and no half pixels.
51- return CGSize ( width: width, height: ceil ( computedSize. height) )
52- case . fixed( let size) :
53- return size
54- case . intrinsic:
55- return view. systemLayoutSizeFitting ( UIView . layoutFittingCompressedSize)
56- }
57- }
58-
5919 /// Initializes a `UIViewContainer`
6020 /// - Parameters:
6121 /// - view: `UIView` being previewed
6222 /// - layout: The layout to apply on the `UIView`. Defaults to `intrinsic`.
63- public init ( _ view : @autoclosure ( ) -> Child , layout: Layout = . intrinsic) {
64- self . view = view ( )
23+ public init ( _ viewCreator : @escaping @autoclosure ( ) -> Child , layout: Layout = . intrinsic) {
24+ self . viewCreator = viewCreator
6525 self . layout = layout
66-
67- switch layout {
68- case . intrinsic:
69- return
70- case . fixed( let size) :
71- self . view. widthAnchor. constraint ( equalToConstant: size. width) . isActive = true
72- self . view. heightAnchor. constraint ( equalToConstant: size. height) . isActive = true
73- case . fixedWidth( let width) :
74- self . view. widthAnchor. constraint ( equalToConstant: width) . isActive = true
75- }
76- }
77-
78- /// Applies the correct size to the SwiftUI `View` container.
79- /// - Returns: A `View` with the correct size applied.
80- public func fixedSize( ) -> some View {
81- let size = self . size
82- return frame ( width: size. width, height: size. height, alignment: . topLeading)
83- }
84-
85- /// Creates a preview of the `UIViewContainer` with the right size applied.
86- /// - Returns: A preview of the container.
87- public func preview( displayName: String ? = nil ) -> some View {
88- return fixedSize ( )
89- . previewLayout ( . sizeThatFits)
90- . previewDisplayName ( displayName)
9126 }
9227}
9328
9429// MARK: Preview + UIViewRepresentable
9530
9631@available ( iOS 13 , * )
9732extension UIViewContainer : UIViewRepresentable {
33+ public func makeCoordinator( ) -> UIViewContainingCoordinator < Child > {
34+ // Create an instance of Coordinator
35+ Coordinator ( viewCreator, layout: layout)
36+ }
9837
99- public func makeUIView( context: Context ) -> UIView {
100- return view
38+ public func makeUIView( context: Context ) -> IntrinsicContentView < Child > {
39+ context . coordinator . createView ( )
10140 }
10241
103- public func updateUIView( _ view: UIView , context: Context ) { }
42+ public func updateUIView( _ view: IntrinsicContentView < Child > , context: Context ) {
43+ update ( view. contentView, coordinator: context. coordinator, updateContentSize: true )
44+
45+ }
10446}
10547
106- @available ( iOS 13 . 0 , * )
107- extension UIViewContainer : KeyPathReferenceWritable {
108- public typealias T = Child
109-
110- public func set< Value> ( _ keyPath: ReferenceWritableKeyPath < Child , Value > , to value: Value ) -> Self {
111- view [ keyPath: keyPath] = value
112- return self
48+ extension UIViewContainer : UIViewContaining {
49+ public func update( _ uiView: Child , coordinator: UIViewContainingCoordinator < Child > , updateContentSize: Bool ) {
50+ guard updateContentSize else { return }
51+ coordinator. view? . updateContentSize ( )
11352 }
11453}
0 commit comments