The SwiftUI ScrollView
lacks some options I would like and so I created a customized MyScrollView
primarily based on UIScrollView
wrapped inside a UIViewControllerRepresentable
. Whereas this works nice typically I do know got here throughout a really unusual drawback:
When MyScrollView
is utilized in a sheet and its content material touches backside SafeArea, the UI freezes as quickly because the ought to be displayed.
The code under exhibits the issue as properly in preview as on the simulator and on units. Please observe that the code is tuned do the show measurement of an iPhone 16 Professional. When working on totally different units one would possibly want to regulate top of the Shade.yellow
.
Within the demo code the UI freezes if the Shade.yellow
has a top between 738 to 771 pixels. Each different top is ok.
Is there one thing fallacious with my implementation of MyScrollView
? When utilizing ScrollView
as a substitute, all the things works nice.
Code:
struct ContentView: View {
@State non-public var showSheet: Bool = false
var physique: some View {
ZStack {
Button("Present Sheet") {
showSheet = true
}
}
.sheet(isPresented: $showSheet) {
VStack {
Textual content("Some Header Content material")
MyScrollView {
VStack {
Shade.yellow
//.body(top: 737) // works
.body(top: 738) // does NOT works
// ...
//.body(top: 771) // does NOT works
//.body(top: 772) // works
}
}
.ignoresSafeArea()
}
}
}
}
struct MyScrollView: UIViewControllerRepresentable {
let content material: Content material
init(@ViewBuilder content material: () -> Content material) {
self.content material = content material()
}
func makeUIViewController(context: Context) -> UIViewController {
let scrollViewVC = UIViewController()
scrollViewVC.view.backgroundColor = .clear
let scrollView = UIScrollView()
scrollView.backgroundColor = .clear
let contentVC = UIHostingController(rootView: self.content material)
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 material
}
func makeCoordinator() -> Coordinator {
return Coordinator()
}
class Coordinator {
var contentVC: UIHostingController?
var scrollView: UIScrollView?
init() {
//...
}
}
}
#Preview {
ContentView()
}