Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save frehulfd/1e98dbbb8b8e527524af5687fe09408e to your computer and use it in GitHub Desktop.
Save frehulfd/1e98dbbb8b8e527524af5687fe09408e to your computer and use it in GitHub Desktop.
Demonstrates how to respect a UIViewController's preferredContentSize while hosted in a UIViewControllerRepresentable
import UIKit
import SwiftUI
import Combine
import PlaygroundSupport
let image1 = #imageLiteral(resourceName: "FKCLjJCWQAsnvY0.jpeg")
let image2 = #imageLiteral(resourceName: "tim-cook-apple-11 (dragged).jpg")
struct TestView: View {
var body: some View {
ScrollView {
VStack(alignment: .center) {
Spacer()
Text("This view's size hugs, as expected.")
.background(Color.blue)
Spacer()
HostView(image: image1)
Spacer()
HostView(image: image2)
Spacer()
}
.background(Color.gray)
}
}
}
struct HostView: View {
let image: UIImage
@State private var preferredContentSize: CGSize? = nil
var body: some View {
HostingView(image: image) { size in
preferredContentSize = size
}
.frame(width: preferredContentSize?.width, height: preferredContentSize?.height)
}
}
struct HostingView: UIViewControllerRepresentable {
let image: UIImage
let preferredContentSizeDidChange: (CGSize) -> Void
func makeUIViewController(context: Context) -> HostingViewController {
let vc = HostingViewController(image: image)
vc
.publisher(for: \.preferredContentSize)
.removeDuplicates()
.sink(receiveValue: preferredContentSizeDidChange)
.store(in: &context.coordinator.cancellables)
return vc
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
}
final class Coordinator {
var cancellables = Set<AnyCancellable>()
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
}
class HostingViewController: UIViewController {
let image: UIImage
init(image: UIImage) {
self.image = image
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError()
}
override func loadView() {
let container = UIView()
container.backgroundColor = .orange
let imageView = UIImageView(image: image)
container.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
imageView.setContentHuggingPriority(.required, for: .horizontal)
NSLayoutConstraint.activate([
imageView.widthAnchor.constraint(lessThanOrEqualTo: container.widthAnchor, multiplier: 1),
imageView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: container.trailingAnchor),
imageView.topAnchor.constraint(equalTo: container.topAnchor),
imageView.bottomAnchor.constraint(equalTo: container.bottomAnchor),
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: image.size.height / image.size.width)
])
view = container
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("Bounds: \(view.bounds)")
preferredContentSize = view.systemLayoutSizeFitting(view.bounds.size, withHorizontalFittingPriority: .defaultHigh, verticalFittingPriority: .fittingSizeLevel)
print("\(preferredContentSize)")
}
}
PlaygroundPage.current.setLiveView(TestView().frame(width: 400, height: 700))
@frehulfd
Copy link
Author

Image files
tim-cook-apple-11 (dragged)
FKCLjJCWQAsnvY0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment