애플의 공식문서 - Preferring one gesture over another를 참고하였습니다.
- 동시에 두 개의 Gesture Recognizer를 달고 있을 경우, 어떻게 핸들링을 하면 될까?
- 답: Gesture Recognizer Delegate Object를 활용하여 뷰에서 어떤 gesture를 먼저 인식할 지를 설정해줄 수 있다.
두 개의 예시를 통해서 한번 확인해보자.
예시 1
- 만약 내가 탭 이벤트와 더블 탭 이벤트를 받아야된다면?
- gestureRecognizer(_:shouldRequireFailureOf:)
- 두 제스처 인식기 사이에 "실패 요구사항"을 설정할지 결정한다.
- Default 값은 false이다.
- true일 경우
- GestureRecongnizer와 OtherGestureRecognizer 사이의 실패 요구조건이 적용이된다.
- 즉, OtherGestureRecognizer가 실패하면 GestureRecognzier가 발동이 된다.
- false일 경우
- GestureRecognizer는 OtherGestureRecognizer가 실패하는 조건을 필요로 하지 않는다.
- 매 인식 시도마다 한번씩 호출이된다.
- 서로 다른 뷰 계층에 있는 인식기들 사이에서도 사용이 가능하다.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
// Don't recognize a single tap until a double-tap fails.
if gestureRecognizer == self.tapGesture &&
otherGestureRecognizer == self.doubleTapGesture {
return true
}
return false
}
( * double tap gesture는 numberOfTapsRequired로 설정할 수 있다.)
예시 2
- 만약 Swipe Gesture를 받고, PanGesture를 받고 싶지 않다면?
- 기본적으로 Pan Gesture는 continuous합니다. 따라서 Swipe Gesture보다 Pan Gesture를 먼저 우선으로 인식합니다.
- gestureRecognizer(_:shouldBeRequiredToFailBy:)
- 한 제스처 인식기가 다른 제스처 인식기에 의해 실패해야 하는지를 결정한다.
- Default는 false이다.
- true일 경우
- gestureRecognizer는 otherGestureRecognizer가 성공하기 전에 반드시 실패해야한다.
- 즉, gestsureRecognzier가 먼저 실행이된다. -> GestureRecognizer가 실패야해야지 otherGestureRecognizer가 실행된다.
- gestureRecognizer는 otherGestureRecognizer가 성공하기 전에 반드시 실패해야한다.
- false일 경우
- GestureRecognizer는 OtherGestureRecognizer가 실패하는 조건을 필요로 하지 않는다.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
// Do not begin the pan until the swipe fails.
if gestureRecognizer == self.swipeGesture &&
otherGestureRecognizer == self.panGesture {
return true
}
return false
}
- 위의 예시의 경우
- 먼저 시스템은 스와이프 제스처를 인식한다. 그리고 만약 스와이프가 아니라면, 팬 제스처가 인식이 된다.
- 즉, 스와이프인 지 확인을 하고, 스와이프가 아니라면 팬 제스처를 인식한다.
즉, 두 개 메소드의 차이는 아래와 같다.
- gestureRecognizer(_:shouldRequireFailureOf:)
- 의미: "A는 B가 실패해야 작동한다"
- 예시: 탭(A)은 더블 탭(B)이 실패해야 인식된다.
- gestureRecognizer(_:shouldBeRequiredToFailBy:)
- 의미: "A는 B가 작동하기 전에 실패해야 한다"
- 예시: 스와이프(A)는 팬 제스처(B)가 인식되기 전에 실패해야 한다.
- A가 실패되어야지 B가 인식이된다.
- 즉, 두 개는 같은 결과를 만들어낼 수 있지만 어떤 것에 중심으로 두고 해석하냐에 따라서 다른 것이다!
즉, 아래와 같이 구현을 해줄 수 있다. 만약 내가 Swipe Gesture가 실패해야지 Pan Gesture를 인식시키고 싶다면? → (Swipe Gesture를 먼저 인식시키고 싶다면)
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer is UISwipeGestureRecognizer && otherGestureRecognizer is UIPanGestureRecognizer {
return true
}
return false
}
근데 만약 내가 동시에 여러 Gesture를 실행시키고 싶을 경우가 생길 수 있다.
마치 하나의 앱에서 Drag, Scale, Rotate를 동시에할 수도 있다. 이럴 경우, gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:) 이걸 활용하면 된다.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer)
-> Bool {
// 만약 gesture가 아래 세 개의 View 안에서 생긴 것이 아니라면 동시 인식을 허용하지 않는다.
if gestureRecognizer.view != self.yellowView &&
gestureRecognizer.view != self.cyanView &&
gestureRecognizer.view != self.magentaView {
return false
}
// 만약 서로 다른 뷰에서 발생할 경우, 동시 인식을 허용하지 않는다.
if gestureRecognizer.view != otherGestureRecognizer.view {
return false
}
// 만약 LongPressGestureRecognizer라면 동시 인식을 허용하지 않는다.
if gestureRecognizer is UILongPressGestureRecognizer ||
otherGestureRecognizer is UILongPressGestureRecognizer {
return false
}
return true
}
'iOS' 카테고리의 다른 글
[iOS] 특정영역만으로 QR 코드 스캔하기(feat. AVFoundation) (0) | 2024.06.26 |
---|---|
[iOS] TabbarController의 presentingViewController(feat.currentContext) (0) | 2024.03.26 |
[iOS] JSONEncoding과 URLEncoding의 차이점(Alamofire/Moya) (1) | 2024.03.05 |
[iOS] CollectionView Reordering (feat. WWDC 20) (3) | 2023.09.15 |
[iOS] Core Location Unit Test하기(feat. WWDC18) (0) | 2023.07.23 |