Last active
January 26, 2022 15:47
-
-
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
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 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)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Image files