티스토리 뷰

반응형

안녕하세요 :) Zedd입니다.

알아두면 좋은 사실을 발견해서 글 씁니댜

제 이전글인 Pan Gesture를 보셨나요?

상하좌우로 드래깅하는 Gesture를 감지할 수 있었는데요, 제가 예제로 사용한건 그냥 View에서의 imageView였죠.

그런데 이걸 ScrollView에서 하고싶다면?

아시다시피, ScrollView는 위 아래로 드래그?..뭐라해야하지 슝슝하고 위아래 스크롤링을 하잖아요?

그걸 어떻게 감지할거냐? 입니다.



이 질문에 이렇게 대답할 수 있겠죠

A : ScrollView Delegate를 이용하면 된다!


하지만, ScrollView Delegate를 이용하면 



이렇게 움직일때마다 메소드가 불려지는게 아닌, 스크롤을 시작했을 때 한번. 딱 한번씩만 불리더라구요.

위 움짤처럼 위, 아래로 움직일때마다 엄청 많이 action이 불려지게 하고싶다!를 구현하려면 어떻게 해야할까요?


저는 이전글에서 Pan Gesture를 배웠으니 Pan Gesture Recognizer를 이용하면 어떻게 되지 않을까? 했습니다. 



  1. 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 호출이 안된다면


아 ㅎ그럼 못하나...하는 도중에 신기한 메소드를 발견했습니다. 

바로 


  1.  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도 "동시인식"이 되겠네요.


  1.  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool{

            return true

        }


이제 그러면?!?!

이제 그러면 실행될까요? 아니죠. 

Delegate에서 가장 중요한 채택과.....대리자 위임을 잊지말아야겠죠? 


 

이렇게 채택을 해주시고, viewDidLoad()에서 대리자 위임을 해줍시다. 



  1.   override func viewDidLoad() {

            super.viewDidLoad()

            let panGestureRecongnizer = UIPanGestureRecognizer(target: self, action: #selector(panAction(_ :)))

            panGestureRecongnizer.delegate = self

            self.view.addGestureRecognizer(panGestureRecongnizer)

    }


이제 그러면?!?!



키키


이참에 그냥 UIGestureRecognizerDelegate에 무슨 메소드가 있는지 다 한번 봐봅시다.

별로 안많아서 ㅎㅎ



  1.  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에서 상태를 전환하려고 한다..라고 하는게 이제 이해가 가시죠?


이 다음이 위에서 봤던 


  1.  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool



이 메소드인데 위에서 설명했으니 넘어갈게요 :)



  1.  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의 차이점을 볼까요? 


shouldRequireFailureOfgesture Recognizer가 다른 gesture Recognizer를 실패 하도록 해야하는 경우, 위임자에게 요청합니다. 


shouldBeRequiredToFailBygesture Recognizer가 다른 gesture Recognizer에 의해 실패해야하는 경우 위임자에게 요청합니다. 


이런 소소한 차이가...

다음으로 넘어갑시다.


  1.  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입니다.


그리고 마지막 메소드!

  1.  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 ☃️



반응형