티스토리 뷰
iOS ) ScrollView에서 위아래 Gesture를 감지하고싶다면? / UIGestureRecognizerDelegate
Zedd0202 2017. 12. 26. 16:21안녕하세요 :) Zedd입니다.
알아두면 좋은 사실을 발견해서 글 씁니댜
제 이전글인 Pan Gesture를 보셨나요?
상하좌우로 드래깅하는 Gesture를 감지할 수 있었는데요, 제가 예제로 사용한건 그냥 View에서의 imageView였죠.
그런데 이걸 ScrollView에서 하고싶다면?
아시다시피, ScrollView는 위 아래로 드래그?..뭐라해야하지 슝슝하고 위아래 스크롤링을 하잖아요?
그걸 어떻게 감지할거냐? 입니다.
이 질문에 이렇게 대답할 수 있겠죠
A : ScrollView Delegate를 이용하면 된다!
하지만, ScrollView Delegate를 이용하면
이렇게 움직일때마다 메소드가 불려지는게 아닌, 스크롤을 시작했을 때 한번. 딱 한번씩만 불리더라구요.
위 움짤처럼 위, 아래로 움직일때마다 엄청 많이 action이 불려지게 하고싶다!를 구현하려면 어떻게 해야할까요?
저는 이전글에서 Pan Gesture를 배웠으니 Pan Gesture Recognizer를 이용하면 어떻게 되지 않을까? 했습니다.
let panGestureRecongnizer = UIPanGestureRecognizer(target: self, action: #selector(panAction(_ :)))
self.view.addGestureRecognizer(panGestureRecongnizer)
@objc func panAction (_ sender : UIPanGestureRecognizer){
let velocity = sender.velocity(in: tableView)
if abs(velocity.x) > abs(velocity.y) {
velocity.x < 0 ? print("left") : print("right")
}
else if abs(velocity.y) > abs(velocity.x) {
velocity.y < 0 ? print("up") : print("down")
}
}
그래서 이렇게 저번 시간에 배운걸 적극 활용했음 ㅎ
(저번시간에는 스토리보드로 UIPanGestureRecognizer를 줬지만 이번엔 코드로 줬습니다.)
엥.......ㅎ왜 안불려..
왜냐하면 ScrollView에는 이미 Gesture가 있거든요 위 아래...그래서 우리의 위 아래 Pan Gesture를 먹어버리는 겁니다.
예전에 ScrollView가 터치이벤트를 먹는다는 것도 글 썼었는데!! 참고해주세요 :)
: ScrollView에서 touchBegan 호출이 안된다면
아 ㅎ그럼 못하나...하는 도중에 신기한 메소드를 발견했습니다.
바로
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
이 메소드죠.
UIGestureRecognizerDelegate가 있는 거 혹시 아시고 계셨나요!? 저는 몰랐움...
위 메소드는 UIGestureRecognizerDelegate의 메소드입니다.
뭘 하는 메소드냐?
gestureRecognizer 또는 otherGestureRecognizer 중 하나의 인식이 다른 것에 의해 차단될 때 호출됩니다.
양 쪽 모두가 동시에 인식할 수 있도록 하려면 true를 반환합니다. 디폴트는 false입니다. (기본적으로 두개의 Gesture는 동시에 인식할 수 없습니다.)
참고 : true를 반환하면 동시 인식이 보장(guaranteed)됩니다. false를 반환해도 다른 Gesture의 대리자가 true를 반환 할 수 있으므로 동시 인식을 방지할 수는 없습니다.
ㄷㄷ
딱 지금 우리의 상태네요. 우리는 Pan Gesture를 분명히 등록해줬는데, ScrollView에 원래있던 위아래로 스크롤링하는 Gesture에 의해 차단된 상태니까요.
그러면 이 메소드에서 true를 반환해주면 우리가 등록해줬던 Pan Gesture도 "동시인식"이 되겠네요.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool{
return true
}
이제 그러면?!?!
이제 그러면 실행될까요? 아니죠.
Delegate에서 가장 중요한 채택과.....대리자 위임을 잊지말아야겠죠?
이렇게 채택을 해주시고, viewDidLoad()에서 대리자 위임을 해줍시다.
override func viewDidLoad() {
super.viewDidLoad()
let panGestureRecongnizer = UIPanGestureRecognizer(target: self, action: #selector(panAction(_ :)))
panGestureRecongnizer.delegate = self
self.view.addGestureRecognizer(panGestureRecongnizer)
}
이제 그러면?!?!
키키
이참에 그냥 UIGestureRecognizerDelegate에 무슨 메소드가 있는지 다 한번 봐봅시다.
별로 안많아서 ㅎㅎ
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
이름에서 볼 수 있듯이 GestureRecognizer가 인식을 시작한다는 것 같죠?
맞습니다. Gesture Recognizer가 UIGestureRecognizerStatePossible에서 상태를 전환하려고 하면 호출되는 메소드입니다.
만약 이 메소드에서 false를 반환하면 UIGestureRecognizerStateFailed로 전환됩니다.
이게 무슨소리인가...싶으실텐데요. 제가 Gesture시리즈를 적으면서 각 Gesture마다 언제 state가 전환되는지 썼을텐데, began, changed, ended이런것들요!!
began, changed, ended이 상태 말고도, possible이라는 상태가 있답니다.
이 possible은 Gesture Recognizer가 아직 Gesture를 인식하지는 못했지만, 터치이벤트는 평가(evaluating)할 수 있는 상태를 의미해요. 이 possible이 기본 상태랍니다.
그러니까 위에서 UIGestureRecognizerStatePossible에서 상태를 전환하려고 한다..라고 하는게 이제 이해가 가시죠?
이 다음이 위에서 봤던
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
이 메소드인데 위에서 설명했으니 넘어갈게요 :)
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool
자....제가 보고 아니 얘네 모가다르지..?한 메소드들입니다. 잘 보시면... 위에거는 그냥 should고 밑에거는 shouldBe에요......................
그리고 should 뒤에는 of가, shouldBe 뒤에는 By가 와있네요.
ㅇ ㅏ....ㅇ....ㅎ....
설명을 얼른 봅시다.
한번의 인식 시도에 한번만 호출되므로 실패 요구 사항이 지연(lazily)될 수 있습니다. 그리고 View계층에서 recognizers간에 설정할 수 있습니다.
gestureRecognizer와 otherGestureRecognizer간에 동적 장애 요구 사항을 설정하려면 true를 반환합니다.
참고 : true를 반환하면 실패 요구 사항이 설정됩니다. false를 반환해도 다른 gesture의 대리자 또는 하위 클래스 메소드가 true를 반환할 수 있으므로 실패 요구 사항이 없음을 보장하지 않습니다.
잘은 모르겠지만, 이 gesture인식이 "실패"했을 때의 처리를 여기서 하는 것 같네요.
그럼 should~of와 shouldBe~By의 차이점을 볼까요?
shouldRequireFailureOf : gesture Recognizer가 다른 gesture Recognizer를 실패 하도록 해야하는 경우, 위임자에게 요청합니다.
shouldBeRequiredToFailBy : gesture Recognizer가 다른 gesture Recognizer에 의해 실패해야하는 경우 위임자에게 요청합니다.
이런 소소한 차이가...
다음으로 넘어갑시다.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
touchesBegan:withEvent:는 새로운 touch를 위해 gesture Recognizer에서 호출됩니다.
gesture Recognizer가 이 touch를 보지 못하게 하려면 false를 반환합니다.
그러니까 한마디로 UIKit은 gesture Recognizer의 touchesBegan (_ : with :) 메소드를 호출하기 전에 위 메소드를 호출한다는 것이죠.
gesture Recognizer에서 touch객체를 검사할 수 있게 하려면 true를 반환하고, gesture Recognizer에서 touch객체를 볼 수 없게 하려면 false를 반환하면 됩니다. 기본값은 true입니다.
그리고 마지막 메소드!
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive press: UIPress) -> Bool
before pressBegan : withEvent :는 새로운 gesture Recognizer에서 호출됩니다. gesture Recognizer가 이 press를 보지 못하게 하려면 false를 반환합니다.
역시 앞서 본 메소드와 비슷합니다. UIKit은 gesture Recognizer의 pressBegan (_ : with :) 메소드보다 먼저 이 메소드를 호출합니다. gesture Recognizer가 press객체를 검사할 수 있도록 하려면 true를 반환하고 gesture Recognizer가 press객체를 볼 수 없도록 하려면 false를 반환하면 됩니다. 기본값은 true입니다 :)
자..이렇게 UIGestureRecognizerDelegate에 있는 메소드들을 다 봤습니댱
오늘도 새로운 사실들을 알아가네요 :)
도움이 되었으면 좋겠습니다 XD ☃️
'iOS' 카테고리의 다른 글
iOS ) UIView와 NSView의 차이 (0) | 2017.12.29 |
---|---|
iOS ) View/레이아웃 업데이트 관련 메소드 (12) | 2017.12.28 |
iOS ) Gesture Recognizer - Pan (7) | 2017.12.22 |
iOS ) Swift에서의 namespace (0) | 2017.12.20 |
iOS ) Archive시 No such module에러가 난다면? (0) | 2017.12.20 |
- swift sort
- ios 13
- np-complete
- WWDC
- swift tutorial
- np-hard
- WidgetKit
- FLUTTER
- actor
- 피아노
- github
- swift3
- iOS delegate
- 스위프트 문법
- swift array
- Swift
- 제이슨 파싱
- SwiftUI
- Accessibility
- swift 공부
- Xcode
- 스위프트
- 회고
- swift delegate
- IOS
- WKWebView
- Combine
- fastlane
- Git
- UIBezierPath
- Total
- Today
- Yesterday