Skip to content

Instantly share code, notes, and snippets.

@Tunous
Created November 9, 2022 14:55
Show Gist options
  • Save Tunous/1935b016a0cd91472fc8bd3036ffe051 to your computer and use it in GitHub Desktop.
Save Tunous/1935b016a0cd91472fc8bd3036ffe051 to your computer and use it in GitHub Desktop.
SwiftUI view wrapper for UIKit that calculates its size
import SwiftUI
final class SwiftUIView<Content: View>: UIView {
private var heightConstraint: NSLayoutConstraint?
init(content: Content, onSizeChanged: @escaping (CGSize) -> Void) {
super.init(frame: .zero)
let sizeReadingContent = content.readSize { [weak self] newSize in
self?.heightConstraint?.constant = newSize.height
self?.heightConstraint?.isActive = true
onSizeChanged(newSize)
}
let host = UIHostingController(rootView: sizeReadingContent)
let hostedView: UIView = host.view
hostedView.backgroundColor = .clear
addSubview(hostedView)
hostedView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostedView.leadingAnchor.constraint(equalTo: leadingAnchor),
hostedView.trailingAnchor.constraint(equalTo: trailingAnchor),
hostedView.topAnchor.constraint(equalTo: topAnchor),
hostedView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
self.heightConstraint = hostedView.heightAnchor.constraint(equalToConstant: 0)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension View {
func readSize(_ onSizeChanged: @MainActor @escaping (CGSize) -> Void) -> some View {
background {
GeometryReader { geometry in
Color.clear.assign(geometry.size, to: onSizeChanged)
}
}
}
func assign<Value: Equatable>(_ value: @autoclosure () -> Value, to action: @MainActor @escaping (Value) -> Void) -> some View {
let computedValue = value()
return task(id: computedValue) {
await action(computedValue)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment