UIScrollView in UIViewControllerRepresentable - UI freezes when content touches bottom SafeArea

The SwiftUI ScrollView lacks some features I need and so I created a custom MyScrollView based on UIScrollView wrapped within a UIViewControllerRepresentable. While this works fine in general I know came across a very strange problem:

When MyScrollView is used in a sheet and its content touches bottom SafeArea, the UI freezes as soon as the should be displayed.

The code below shows the problem as well in preview as on the simulator and on devices. Please note that the code is tuned do the display size of an iPhone 16 Pro. When running on different devices one might need to adjust height of the Color.yellow.

In the demo code the UI freezes if the Color.yellow has a height between 738 to 771 pixels. Every other height is fine.

Is there something wrong with my implementation of MyScrollView? When using ScrollView instead, everything works fine.

Code:

struct ContentView: View {
@State private var showSheet: Bool = false
var body: some View {
ZStack {
Button("Show Sheet") {
showSheet = true
}
}
.sheet(isPresented: $showSheet) {
VStack {
Text("Some Header Content")
MyScrollView {
VStack {
Color.yellow
//.frame(height: 737) // works
.frame(height: 738) // does NOT works
// ...
//.frame(height: 771) // does NOT works
//.frame(height: 772) // works
}
}
.ignoresSafeArea()
}
}
}
}
struct MyScrollView<Content: View>: UIViewControllerRepresentable {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
func makeUIViewController(context: Context) -> UIViewController {
let scrollViewVC = UIViewController()
scrollViewVC.view.backgroundColor = .clear
let scrollView = UIScrollView()
scrollView.backgroundColor = .clear
let contentVC = UIHostingController(rootView: self.content)
contentVC.view.backgroundColor = .clear
context.coordinator.contentVC = contentVC
context.coordinator.scrollView = scrollView
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollViewVC.view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: scrollViewVC.view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: scrollViewVC.view.bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: scrollViewVC.view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: scrollViewVC.view.trailingAnchor)
])
contentVC.willMove(toParent: scrollViewVC)
scrollViewVC.addChild(contentVC)
contentVC.view.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(contentVC.view)
NSLayoutConstraint.activate([
contentVC.view.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
contentVC.view.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
contentVC.view.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
contentVC.view.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
contentVC.view.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor)
])
contentVC.didMove(toParent: scrollViewVC)
return scrollViewVC
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
context.coordinator.contentVC?.rootView = content
}
func makeCoordinator() -> Coordinator {
return Coordinator()
}
class Coordinator {
var contentVC: UIHostingController<Content>?
var scrollView: UIScrollView?
init() {
//...
}
}
}
#Preview {
ContentView()
}

Something I ran into is that if a viewcontroller's view is a UIStackView there is a layout loop created that crashes when it runs out of stack space. This happened if the stack view impinged into the safe area. Making it the subview of a UIView fixed it. This happened using UIKit.

Meanwhile I have received a response to my DTS ticket. However, the proposed solution does not really fix the problem:

Since this is a sheet, you’ll want to constrain the anchors to the ViewControllers safeAreaLayoutGuide instead since the sheet doesn’t have a status bar.
For example:

NSLayoutConstraint.activate([
scrollView.topAnchor
.constraint(equalTo: scrollViewVC.view.safeAreaLayoutGuide.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: scrollViewVC.view.safeAreaLayoutGuide.bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: scrollViewVC.view.safeAreaLayoutGuide.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: scrollViewVC.view.safeAreaLayoutGuide.trailingAnchor)
])

When using this code, the UI does not freeze anymore. However, this is just because now the scroll view does not reach below the SafeArea any more. This is obviously not a solution to the problem: How to avoid the UI from freezing when the scroll content reaches below the SafeArea?

UIScrollView in UIViewControllerRepresentable - UI freezes when content touches bottom SafeArea
 
 
Q