Skip to content

Instantly share code, notes, and snippets.

@YanSte
Last active August 18, 2022 08:01
Show Gist options
  • Save YanSte/544d73b4f077c00bfb8cde0a218f4c8d to your computer and use it in GitHub Desktop.
Save YanSte/544d73b4f077c00bfb8cde0a218f4c8d to your computer and use it in GitHub Desktop.
UIWrapping, Wrapping UIKit to SwiftUI
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