[iOS] hitTest 란?

ellyheetov·2022년 8월 4일
0

나의 터치 이벤트에 반응한 뷰가 누구인지 알아보기 위해 필요한 것이 hitTest!

HitTest 란

hitTest의 목적은 터치 이벤트가 발생한 최상단의 뷰를 찾기 위함이다.

point를 포함하고 있는 View에서 가장 멀리 떨어진 View(= 최상단의 뷰)를 반환한다.

최상단의 뷰가 누구?

여기서 말하는 최상단의 뷰는 View의 hierarcy에서 가장 상위 (ex. UIWindow) 를 말하는 것일까??

NO!!

최상단의 뷰는 사용자가 보기에 가장 위에 있는 뷰를 의미한다. 가장 앞에 있는 View 라고 볼 수 있다.

위와 같이 View A와 View B가 겹쳐저 있는 부분을 터치를 했을 때 가상 상위에 있는 View는 B이다.

hitTest는 언제 사용하는 거야?

hitTest를 이용하면 사용자의 터치 이벤트를 받는 View를 정할 수 있다.

예를 들어, View B의 hitTest를 이용하여 그림에서와 같은 위치를 터치하더라도 View A를 터치한 것과 같은 효과를 낼 수 있다.

hitTest는 어떻게 사용하는 거야?

결론 부터 말하자면, View B에서 이벤트를 처리하지 않도록 hitTest에서 nil을 반환 하면 된다.

class ViewB: UIView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let hitview = super.hitTest(point, with: event)
        return hitview == self ? nil : hitview
    }
}

nil을 반환하는 경우 해당 이벤트를 처리하지 않고, 이벤트에 반응할 다른 View를 찾으러 간다. View B 다음으로 가장 최상단에 있는 View는 View A 이므로, View A가 이벤트를 처리하게 된다.

HitTest 동작 원리

hitTest는 가장 앞에 있는 View(= 최상단에 있는 View) 를 찾기 위해서 View 계층을 탐색한다. 이때, 이용하는 방식이 reverse pre-order DFS(Depth-first-traversal) 이다.

  • reverse pre-order DFS

예시로 든 화면의 뷰 계층을 그림으로 나타내자면 다음과 같다.

만약 View B의 hitTest에서 nil을 반환하게 한다면 어떻게 될까?

다음 최상위 뷰를 찾기 위하여 View A를 탐색하게 되고, 그 결과 터치 이벤트에 반응하는 객체는 View A가 된다.

결과적으로 View B는 hitTest에서 nil을 반환함으로써 View A에게 touch event를 전달 한 것이다.

더 복잡하게

그럼 이제, Apple에서 제공하는 예시를 이해해 보자.

여러개의 View가 있고, 중첩된 구조 이다.
여기서 만약 View B.1 을 터치하면 event는 어떻게 전달될까?

위에서 부터 아래 계층으로 내려오면서 탐색을 진행한다. View C까지 탐색을 하지만, View C는 해당 point를 포함하지 않기 때문에 falsereturn하고, View B로 넘어와서 hitTest를 수행한다. 그 결과 View B.1 을 반환하게 된다.

즉, 해당 뷰 계층에서 가장 최상단에 있는 View는 View B.1이라는 것을 의미한다.

주의할 점

  • View객체가 hidden된 경우
  • user interactoin을 disable 시킨 경우
  • alpha값이 0.01 보다 작은 경우

위 경우에 대해서는 hitTest를 무시한다.

정리

  • HitTest란? 터치한 이벤트에 반응할 최상단 뷰를 찾는 메소드이다.
profile
 iOS Developer 좋아하는 것만 해도 부족한 시간

0개의 댓글