Last active
August 18, 2022 08:01
-
-
Save YanSte/544d73b4f077c00bfb8cde0a218f4c8d to your computer and use it in GitHub Desktop.
UIWrapping, Wrapping UIKit to SwiftUI
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 SwiftUI | |
/// Provides a convenient 'wrapper' around a UIView | |
public struct UIWrapping<V>: View { | |
let wrapped: AnyView | |
public var body: some View { wrapped } | |
// MARK: Initializers | |
/// Instantiates a wrapper for a `UIView` | |
/// - Parameters: | |
/// - viewProvider: Use this closure to return an instantiated `UIView` | |
/// - updateHandler: Use this closure to configure the view, this is called for all SwiftUI view updates as well | |
public init(_ provider: @escaping RepresentableProvider<V>, update handler: RepresentableUpdater<V>? = nil) where V: UIView { | |
self.wrapped = AnyView( | |
ViewWrapper( | |
provider: provider, | |
updater: handler | |
) | |
) | |
} | |
/// Instantiates a wrapper for a `UIView` – uses `.init(frame:)` | |
/// - Parameters: | |
/// - type: The type of `UIView` to wrap | |
/// - updateHandler: Use this closure to configure the view, this is called for all SwiftUI view updates as well | |
public init(_ type: V.Type = V.self, update handler: @escaping (V) -> Void) where V: UIView { | |
self.wrapped = AnyView( | |
ViewWrapper( | |
provider: { V(frame: .zero) }, | |
updater: handler | |
) | |
) | |
} | |
/// Instantiates a wrapper for the specified viewProvider | |
/// - Parameters: | |
/// - viewProvider: Use this closure to return an instantiated `UIView` | |
/// - updateHandler: Use this closure to configure the view, this is called for all SwiftUI view updates as well | |
public init(_ provider: @escaping RepresentableProvider<V>, update handler: RepresentableUpdater<V>? = nil) where V: UIViewController { | |
self.wrapped = AnyView( | |
ViewControllerWrapper( | |
provider: provider, | |
updater: handler | |
) | |
) | |
} | |
/// Instantiates a wrapper for a `UIViewController` – uses `.init(nibName:bundle:)` | |
/// - Parameters: | |
/// - type: The type of `UIViewController` to wrap | |
/// - handler: Use this closure to configure the view, this is called for all SwiftUI view updates as well | |
public init(_ type: V.Type = V.self, update handler: @escaping (V) -> Void) where V: UIViewController { | |
self.wrapped = AnyView( | |
ViewControllerWrapper( | |
provider: { V(nibName: nil, bundle: nil) }, | |
updater: handler | |
) | |
) | |
} | |
} | |
// MARK: - Private ViewWrapper | |
public typealias RepresentableProvider<V> = () -> V | |
public typealias RepresentableUpdater<V> = (V) -> Void | |
private struct ViewWrapper<V: UIView>: UIViewRepresentable { | |
let provider: RepresentableProvider<V> | |
let updater: RepresentableUpdater<V>? | |
func makeUIView(context: Context) -> V { | |
provider() | |
} | |
func updateUIView(_ view: V, context: Context) { | |
view.backgroundColor = .clear | |
updater?(view) | |
} | |
} | |
// MARK: - Private ViewControllerWrapper | |
private struct ViewControllerWrapper<V: UIViewController>: UIViewControllerRepresentable { | |
public typealias Provider = () -> V | |
public typealias Updater = (V) -> Void | |
let provider: Provider | |
let updater: Updater? | |
func makeUIViewController(context: Context) -> V { | |
provider() | |
} | |
func updateUIViewController(_ controller: V, context: Context) { | |
controller.view.backgroundColor = .clear | |
updater?(controller) | |
} | |
} | |
// MARK: - Previews | |
struct UIWrapping_Preview: PreviewProvider { | |
static var previews: some View { | |
VStack { | |
UIWrapping<UILabel> { view in | |
view.numberOfLines = 0 | |
view.text = "Hello 😄" | |
view.textAlignment = .center | |
} | |
.fixedSize() | |
UIWrapping<UIActivityIndicatorView> { view in | |
view.startAnimating() | |
} | |
// Note: In case of UICollectionView must be initialized with a non-nil layout parameter. | |
UIWrapping { () -> UICollectionView in | |
let flowLayout = UICollectionViewFlowLayout() | |
flowLayout.scrollDirection = .vertical | |
flowLayout.minimumInteritemSpacing = 0 | |
flowLayout.minimumLineSpacing = 0 | |
flowLayout.sectionInset = .zero | |
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) | |
collectionView.backgroundColor = .black | |
collectionView.showsVerticalScrollIndicator = true | |
return collectionView | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment