Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 15. event의 원리 (hitTest, point, Responder Chain, Touch event) 본문

iOS 기본 (swift)

[iOS - swift] 15. event의 원리 (hitTest, point, Responder Chain, Touch event)

jake-kim 2020. 6. 6. 11:07

1. hitTest(_:with:), point(inside:with:)

- 이벤트 발생한 뷰 탐색 :

    Pre-Order Depth First Traversal Algorithm 사용 (UIWindow부터 시작하며, 최근에 추가된 view먼저 탐색)

- UIWindow를 First Responder라고함(탐색의 시작점이 UIWindow이므로)

- 이벤트가 발생한 뷰를 찾는 것

self.view.addSubview(viewA)
self.view.addSubview(viewB)
self.view.addSubview(viewC)

터치한 뷰를 찾는 과정

1) 뷰의 최상위인 UIWindow가 hitTest(_:with:)호출 -> point(inside:with)로 터치 이벤트가 발생한 곳이 UIWindow내부인지 체크 -> true -> subView도 이어서 탐색

 

2) MainView역시 hitTest(_:with:)메소드를 통해서 1)번과 같은 작업 -> 깊이 순서에 의해 viewC를 가장 먼저 탐색(sibling관계에서는 가장 나중에 추가된 노드를 먼저 방문)

 

3) viewC에서 hitTest(_:with:)는 nil반환, point(inside:with:)는 false반환 -> viewB탐색

 

4) sibling관계에 의해서 viewB.2먼저 탐색 -> view B.1탐색

2. hitTest(_:with:), point(inside:with:) 사용하여 문제 해결하기

button이 투명한 view밑에 존재 할 때, 투명한 view를 눌러도 이 버튼에 이벤트가 발생하게끔 하는 방법?

- 투명한 view를 정의한 클래스에서 override를 이용하여 false를 반환하게끔 함

 

1) point(inside:with:)를 이용한 방법

- false반환

class CustomTransparentView: UIView {
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        return false
    }
}

2) hitTest(_:with:)를 이용한 방법

- 투명한 뷰(자기 자신인 경우 nil반환)

class CustomTransparentView: UIView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        var hitTestView = super.hitTest(point, with: event)
        if hitTestView == self { // 1.
            hitTestView = nil
        }
        return hitTestView
    }
}

class ViewController: UIViewController {
    @IBOutlet weak var transparentView: CustomTransparentView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func buttonDidTapped(_ sender: UIButton) {
        print("Button Did Tapped")
    }
}

3. UIResponder

이벤트를 처리하는 클래스 (이것을 상속받아서 UIView, UIViewContoller, UIWindow탄생, 이것들은 UIResponder메소드들을 재정이)

UIResponder메소드

func touchesBegan(Set<UITouch>, with: UIEvent?)와 같은 메소드 재정의하여 사용

 

4. UIEvent

이벤트가 발생했을 때 그 이벤트에 해당한는 객체로 변환 후 UIResponder객체에게 전달

- 같은 이벤트에 대한 객체는 재사용

 

5. UITouch

터치 이벤트 발생시, 이벤트 객체와 동시에 터치에 관한 정보를 담는 객체

 

* 정보

- 터치가 발생한 윈도우나 뷰

- 터치가 발생한 좌표 : func location(in view: UIView?) -> CGPoint

- 터치의 반지름

- 터치 강조(3D touch)

- 터치 횟수

- 터치한 시점

 

참조 : developer.apple.com/documentation/uikit/uitouch

 

Comments