티스토리 뷰

Mobile/iOS

iOS/swift. hitTest 이용하기

out of coding 2018. 4. 8. 12:56

HitTest


iOS에서 터치가 발생하였을 경우에 이 뷰를 관통할지의 여부를 판단하기 위해서 Hit-Test를 이용합니다.

이 부분에 대해서 개념을 잘 못잡는 분들이 있는것 같아서 글을 적으려 합니다.

근데 이름이 hitTest이다 보니깐 다들 그냥 test를 하는것인데 다르게 생각하면 내가 터치를 사용할지 말지에 대한 테스트입니다. ㅎㅎ 다들 그냥 테스트로만 생각하시는듯... 싶더군요.


자... 모든 화면을 View로 구성이 되어 있습니다.

View위에 View를 그리고 그 위에 View를 그리고 이렇게요.


그렇게 되다보니 제일 위에있는 뷰가 모든 터치를 받게 됩니다.

특정한 조건이 아니라면요. 이 조건이면 터치 이벤트를 받지 않습니다.

기본적으로는 특정 조건이 다음과 같습니다. 


override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    if !isUserInteractionEnabled || isHidden || alpha <= 0.01 {
        return nil
 
    }
 
    if self.point(inside: point, with: event) {
        for subview in subviews.reversed() {
            let convertedPoint = subview.convert(point, from: self)
            if let hitTestView = subview.hitTest(convertedPoint, with: event) {
                return hitTestView
 
            }
        }
 
        return self
    }
 
    return nil
}
cs


isUserInteractionEnabled, isHidden, alpha


그렇습니다. 저희가 개발을 할때 사용하는 옵션들이죠.

그냥 알파를 0으로 주거나 hidden 시키면 해당 공간에는 View는 그대로 존재하는것입니다.

대신 View touch를 통과를 시켜버리는 겁니다.



이것을 가지고 무엇을 할 수 있느냐면


1. 터치 면적 넓히기


기본적으로 버튼에 이미지를 넣고 넓이를 조정하지 않으면 터치가 되는 영역이 이미지의 영역으로만 됩니다.

그러면 작은 버튼의 경우에는 터치를 하기가 너무 힘들어지기 때문에 hitTest를 이용하여 이 부분을 해결을 할 수 있습니다.

예를 든 부분은 10정도씩 터치 영역을 넓힌 상태입니다.


override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    if !isUserInteractionEnabled || isHidden || alpha <= 0.01 {
        return nil
    }
 
    let touchRect = bounds.insetBy(dx: -10, dy: -10)
    if touchRect.contains(point) {
        for subview in subviews.reversed() {
            let convertedPoint = subview.convert(point, from: self)
            if let hitTestView = subview.hitTest(convertedPoint, with: event) {
                return hitTestView
            }
        }
 
        return self
    }
 
    return nil
}
cs


2. 터치 이벤트를 그냥 통과 시키기


제가 좋아하고 잘 사용하는 방법입니다.

ViewController에 view를 addSubView하게 되면 그 아래의 View에 터치를 전달할 수 없습니다.

위 아래의 컴포넌트들은 사용을 하고 싶은데 투명하게 되어 있는 부분은 통과를 시켜 주고 싶을 경우이죠.


override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let hitTestView = super.hitTest(point, with: event)
    if hitTestView == self && touchPassEnable {
        return nil
    } else {
        return hitTestView
    }
}
cs


touchPassEnable 값을 이용하여서 전달을 할것인지 판단을 합니다.


3. SubView에 터치 이벤트 보내기


위의 예제와 거의 동일하지만 일부 뷰만 그리고 아래의 뷰에 터치를 전달하여야 하는 경우가 있을것인데요.

위에 2번처럼 사용을 하면 됩니다.


override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let hitTestView = super.hitTest(point, with: event)
    if hitTestView == self && touchPassEnable {
        return self.targetView
    } else {
        return hitTestView
    }
}
cs

이런저런 예제들은 스택오버플로우에 많이 있는것 같은데.

창의력만 조금 발휘를 한다면 깔끔하게 뷰를 구성하여서 사용할수 있을것 같네요.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함