[UIKit] ScrollView에서 touchesBegan이 호출되지 않는 문제 해결하기

iosSwiftUIKit
avatar
2025.03.05
·
4 min read

문제 상황

UIKit을 사용하여 UIScrollView 내부에서 터치 이벤트(touchesBegan)가 호출되지 않는 이슈가 발생할 수 있다. 특히, UITextField나 UITextView가 포함된 ScrollView에서 키보드를 닫기 위해 터치 이벤트를 감지하려 할 때 이 문제가 종종 발생한다.

문제의 원인:

  1. UIScrollView는 기본적으로 터치이벤트를 인터셉트(Intercept)하여 스크롤 동작을 우선 처리한다.

  2. 따라서, touchesBegan(_: with:)같은 일반적인 터치 이벤트가 호출되지 않을 수 있다.

  3. 키보드를 닫으려면 터치 이벤트를 인식해야 하는데, 이 과정에서 문제가 발생한다.

이 문제를 해결하기 위해 UITapGestureRecognizer를 활용하여 터치 이벤트를 ScrollView에서 감지하는 방법을 사용할 수 있다.

해결 방법

다음과 같이 UITapGestureRecognizer를 사용하여 ScrollView에서 터치 이벤트를 감지하고, 키보드를 닫을 수 있도록 설정할 수 있다.

private func setupTapGesture() {
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
    tapGesture.cancelsTouchesInView = false // 터치 이벤트를 다른 UI 요소로 전달
    scrollView.addGestureRecognizer(tapGesture)
}

@objc private func dismissKeyboard() {
    view.endEditing(true) // 키보드 닫기
}
  • UITapGestureRecognizer를 scrollView에 추가하여 터치를 감지한다.

  • cancelsTouchesInView = false 설정을 통해 터치 이벤트가 다른 UI 요소에도 전달되도록 한다.

  • endEditing(true)를 호출하여 현재 활성화된 키보드를 닫는다.

cancelsTouchesInView = false의 역할

이 코드에서 가장 중요한 부분은 cancelsTouchesInView = false 설정이다.

tapGesture.cancelsTouchesInView = false

cancelsTouchesInView = true (기본값)

  • 터치 이벤트가 GestureRecognizer에서 처리된 후, 다른 UI 요소로 전달되지 않는다.

  • 즉, 터치를 감지할 수 있지만 ScrollView의 터치 이벤트(touchesBegan)가 호출되지 않음.

cancelsTouchesInView = false

  • GestureRecognizer가 터치 이벤트를 가로채지 않고, 다른 UI 요소에도 전달한다.

  • 따라서 touchesBegan(_:with:)과 같은 기본 터치 이벤트가 호출될 수 있다.

이 설정을 적용하면 사용자가 ScrollView를 터치했을 때, 터치 이벤트가 정상적으로 동작하며 동시에 키보드도 닫을 수 있다.

추가적인 고려 사항

  1. 터치 이벤트를 더 명확하게 처리하고 싶다면?

    • gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)을 구현하여 여러 제스처가 동시에 동작할 수 있도록 조정할 수 있다.

      func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
          return true
      }
  2. UIScrollView 내부의 특정 영역에서만 키보드를 닫고 싶다면?

    • tapGesture를 추가할 때 특정 뷰에서만 동작하도록 설정할 수 있다.

      tapGesture.delegate = self
  3. SwiftUI에서 같은 기능을 구현하려면?

    • SwiftUI에서는 onTapGesture를 사용하여 비슷한 기능을 구현할 수 있다.

      ScrollView {
          VStack {
              TextField("입력", text: $text)
                  .textFieldStyle(RoundedBorderTextFieldStyle())
          }
      }
      .onTapGesture {
          UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
      }






- 컬렉션 아티클