UIViewControllerRepresentable로 sheet를 할 때 아랫방향 슬라이딩 제스처가 작동하지 않는 문제

문제

swiftUI로 프로젝트를 진행하다가 PHPickerViewController를 이용해서 이미지를 선택하는 기능을 구현하려고 UIViewControllerRepresentable로 감싸서 이를 sheet로 띄우니 끌어서 닫는 기능이 작동하지 않았다.

일단 뷰 계층을 살펴보니 PresentationHostingController위에 PHPickerViewController가 덮여있는 것을 볼 수 있다. PUPickerRemoteViewController는 뭔지 모름. (검색해도 안 나옴)

원인

구글링 좀 해보니 UIKit의 pan gesture 같은 제스처 이벤트가 UIKit의 ViewController에서 일어날 시, swiftUI의 뷰에 전달하지 않고 ViewController가 그대로 받아 버리는 모양이다. 그래서 pan gesture가 먹히지 않는 것.

해결

화면 전체가 ViewController로 덮인 게 문제인 건가 싶어서 VStack으로 상단에 약간의 공백을 만들어 준 뒤 화면을 띄어보았다.

.sheet(isPresented: $showImagePicker, content: {
                    VStack {
                        RoundedRectangle(cornerRadius: 8).fill(Color.gray)
                                        .frame(width: 60, height: 8)
                                        .padding(.top, 8)
                                        .padding(.bottom, 8)
                        ImagePicker(selectImage: $viewModel.profileImage, currentError: $viewModel.currentError, imageSize: 150)
                    }
            })

이번엔 정상적으로 작동이 된다. viewController부분이 아닌 swiftUI의 View 부분은 정상적으로 제스처가 작동한다.

하지만 iOS 17 버전 이후에서는 이런 짓을 할 필요가 없어졌다. 업데이트되면서 ViewController에서 제스처가 발생해도 정상적으로 제스처를 받을 수 있게 되었다.

뷰 계층을 확인해 보니 PresentationHostingController가 PHPickerViewController에 완전히 덮이지 않았다. PresentationHostingController가 swiftUI이니 이게 완전히 덮히지 않아서 제스처가 작동하는 건가 생각했는데, ViewController 내부에서 제스처 이벤트가 발생했을 때에도 정상적으로 제스처가 작동하는 걸 보니 (PHPicker내부에서 끌어내렸데도 작동) 큰 연관은 없을듯하다..

어쨌든 중요한 점은 iOS 17 이후에는 sheet 할 때 윗부분에 View를 넣지 않아도 되므로

.sheet(isPresented: $showImagePicker, content: {
                if #available(iOS 17.0, *) {
                    ImagePicker(selectImage: $viewModel.profileImage, currentError: $viewModel.currentError, imageSize: 150)
                } else {
                    VStack {
                        RoundedRectangle(cornerRadius: 8).fill(Color.gray)
                                        .frame(width: 60, height: 8)
                                        .padding(.top, 8)
                                        .padding(.bottom, 8)
                        ImagePicker(selectImage: $viewModel.profileImage, currentError: $viewModel.currentError, imageSize: 150)
                    }
                }
            })

이런 식으로 버전별로 대응하도록 구현하였다.

'iOS > SwiftUI' 카테고리의 다른 글

SwiftUI와 Opaque Type, @ViewBuilder  (0) 2024.05.10
SafeAreaRegions  (0) 2023.12.29