6.4 C
New York
Saturday, April 12, 2025

ios – UIScrollView in UIViewControllerRepresentable – UI freezes when content material touches backside SafeArea


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()
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles