[iOS] motion gesture 감지하기

흔들기 제스처를 파악해봅시다

개-하! 릠들 별다방 앱에서 흔들흔들하면 pay가 바로 뜨고 카톡에서 흔들흔들하면 QR 체크인 코드 뜨는거 알구 현생 살구 계시는지..?! (물론 카톡에선 아직 실험실에 있는 기능이라 설정 > 실험실에서 쉐이크 기능 켜야하기하지만여)

🤷🏻‍♀️ ?? 그래서 어케 구현햇????

😎 걍 갖다 쓰면 되어요.. ㅎㅎ

한번 viewController 쪽에 motion을 쳐봅시당

오 뭔가 그럴싸해보이는 삼인방이 있쥬? 한번 공식 문서를 찾아가 봅시다

UIResponder의 instance 메소드였군요! UIViewController도 결국 UIResponder를 상속받고 있으니까 위에서 motion 쳤을때 자동 완성이 나왔던거겠져??

한번 타고 들어가보면..?!! 예에.. 이곳에 진짜 계시네용.. iOS 3부터 지원되셨던 조상님..!

우선 이름만 봐도 대충 언제쓰는 애들인지는 알거 같지만..!! 그래도 문서를 살펴봅시다

1. motionBegan(_:with:)

  • 모션 이벤트가 시작되었다고 receiver 에게 알려줌

Parameters

func motionBegan(_ motion: UIEvent.EventSubtype, 
with event: UIEvent?)
  • motion - EventSubtype 에 해당하는 상수로 motion의 종류를 나타냄. 일반적인 motion 은 shaking.
  • event - motion과 관련된 이벤트를 나타내는 object (흠...?🤔)

흠냐리 흠냐..! motion 파라미터로 어떤 동작을 취하고 있는지 판단할 수 있나보군여. 한번 뜯어봅시다 ㅎㅎ

어우 많다 많어. 기본적으로 motionShake 는 지금 제가 관심있는 흔들기, 나머지 remote~~ 로 시작하는 원격 제어 이벤트는 device의 멀티미디어 제어를 위해 헤드셋 또는 외부 악세러리에서 수신한 command로 발생하는거라고 하네영.

더 자세한건 이렇게 하나씩 알아서 살펴보시고..?!?!!?

다음 메소드로 넘어가 봅시다 (후비적)

2. motionEnded(_:with:)

  • 모션 이벤트가 끝났다고 receiver 에게 알려줌

ㅇㅋㅇㅋ 나머지는 motionBegan 이랑 비슷할거 뻔하쥬?

그리고 여기까지 봤을때 짐작하셨을지 모르겠지만!! 이렇게 UIKit은 모션 이벤트가 시작되고 종료될 때만 responder에게 motionBegan, motionEnded를 통해 알림을 주게 됩니다. 즉, 중간에 발생하는 모션은 report 하지 않는다는 것이져

또한 모션 이벤트는 first responder에게 먼저 전달되고, 필요에 따라 responder chain으로 전달(forward) 되는 특성을 갖고 있습니다 (responder chain을 모르시겠다면 이 글을 추천합니당)

3. motionCancelled(_:with:)

아 그럼 시작도 알고 끝도 알겠는데~~~ 그럼 cancel은 머냐??? 싶으니까 또 애플 문서 긁긁해옵시당

  • 모션 이벤트가 취소 되었다고 receiver 에게 알려줌
  • 모션 이벤트 취소가 필요한 interruption을 수신할 때 UIKit에서 해당 메소드를 호출함.
  • interruption이란 앱을 비활성화시키거나, 모션 이벤트를 처리하는 view를 window에서 제거하는 모든 것을 지칭
  • 아니면 shake 기능이 너무 오래 지속될 경우에도 UIKit이 해당 메소드를 호출 할 수 있음
  • 모션 이벤트를 처리하는 모든 responder는 이 메소드를 구현해서 모션 이벤트 처리와 관련된 상태 정보를 clean up 해야함

Code

자자 이제 코드를 봅시다. 사실 머.. 코드랄것도 없긴해여 ㅎ 그냥 입맛따라 취향따라 골라쓰시면 되는데! 먼가 제가 카톡이나 스벅 같은 기능을 개발했다면 began에 구현해놓지 않았을까여? 사용자가 제스처 빨리 잡아서 띄우는게 목적이니까?

튼 한번 작성해놓고 흔들어제껴보자구여~~~

override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
if motion == .motionShake {
print("시작")
}
}

override func motionCancelled(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
print("취소따리취소따")
}

override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
if motion == .motionShake {
print("끗")
}
}
끗 (x) 끝 (o) 인거 알고 있어여..!

호옹.. 예상대로 잘 동작하쥬?

적당히 흔들다가 멈추면 시작-끗 이 프린트 되고, 계속 흔들어버리면 시작-취소따리취소따 가 프린트됩니다 (shake 기능이 너무 오래 지속될 경우에 UIKitmotionCancelled 를 호출할 수 있다고 했으니까요!)

그리고 아까 모션 이벤트는 first responder에게 먼저 전달되고, 필요에 따라 responder chain으로 전달된다고 했잖아여?! 진짜 그런지 한번 살펴봅시당

class ViewController: BaseViewController {
override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
if motion == .motionShake { print("시작") }
}

override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
if motion == .motionShake { print("끗") }
}
}

class BaseViewController: UIViewController {
override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
if motion == .motionShake { print("Base 시작") }
}

override func motionCancelled(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
if motion == .motionShake { print("Base 취소따리취소따") }
}

override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
if motion == .motionShake { print("Base 끗") }
}
}

뭐 길어보이긴 한데 별거 없어여. ViewControllerBaseViewController를 상속받게 한 후 아까와 달리 motionCancelled 구현부만 삭제했습니다. 그리고 BaseViewController 에서는 다 override 구현해줬쥬

이 상황에선 아까와 같이 1. 적당히 흔들다가 멈추거나, 2. 계속 흔들어버리면 각각 어떻게 프린트가 될까요?

시작-끗시작-Base 취소따리취소따 가 출력되는 것을 확인할 수 있습니다. Base 취소따리취소따가 찍힌 이유는 ViewController의 responder chain에 따라 메시지를 위로 보낸 결과겠지요?

마무리

멋진 기능을 간단하게 구현할 수 있어서 넘 좋네여 ㅎ_ㅎ iOS에서 요러한 기능이 있다는거 알구 필요한 상황에 맞게 잘 쓰시길 바람둥!

그럼 20000!

참고

 https://github.com/sujinnaljin/TIL