CS193P

[iOS] 스탠포드 CS193P 6강

Beck 2021. 8. 31. 19:42

6강에서는 앞서 진행했던 PlayingCard 데모에서 만들었던 카드에 tap, swipe 제스쳐가 발생할 때 카드의 모습을 바꿔주는 데모를 했습니다. 해당 데모는 UIGestureRecognizer를 다루는 것으로 tap, swipe 제스쳐를 처리했고, 각 기능에 대해 소개하는 것으로 6강은 마무리 됐습니다.
이번 6강 정리에서는 UIGestuerRecognizer에 대한 정리와 함께 데모에서 다뤘던 것들을 기록해봤습니다.

UIGestureRecognizer

Gesture Recognizer는 일반적인 제스처나 제스처의 변경을 인지했을 때 지정된 타겟 객체에 동작 메시지를 보냅니다.

var state: UIGestureRecognizerState { get }

UIGestureRecognizer는 상태를 가지는데 그 상태변수는 UIGestureRecognizerState입니다.
이 변수는 .possible 상태에서 시작합니다. 
Continuous 제스처 👉 .began - .changed - .ended
Discrete 제스처 👉 바로 .ended or .recognized

UIGestureRecognizerState

UIGestureRecognizer를 상속받아 사용할 수 있는 8가지 Gesture Recognizer가 있습니다.

  • UITapGestureRecognizer
  • UIPinchGestureRecognizer
  • UIRotationGestureRecognizer
  • UISwipeGestureRecognizer
  • UIPanGestureRecognizer 👉 터치한 손가락이 떨어지지 않고 상하좌우로 움직이는 것
  • UIScreenEdgePanGestureRecognizer 👉 왼쪽, 오른쪽 엣지를 스와이프할 때
  • UILongPressGestureRecognizer
  • UIHoverGestureRecognizer 👉 iOS에서는 작동하지 않고, iPad나 Mac에서 커서가 뷰 위에 있을 때

 

Gesture Reconizer의 변수들

각 제스처 인식기에서 주로 쓰이는 변수들을 나열해봤습니다.

UIPinchGestureRecognizer
두 손가락으로 확대하거나 축소할 때 사용하는 gesture recognizer 입니다.

var scale: CGFloat // not read-only (can reset) 
var velocity: CGFloat { get } // scale factor per second

 

UIRotationGestureRecognizer
두 손가락으로 뷰를 회전시키려고 할 때 사용합니다.

var rotation: CGFloat // not read-only (can reset); in radians 
var velocity: CGFloat { get } // radians per second

 

UISwipeGestureRecognizer
방향과 터치하는 손가락 개수를 설정할 수 있습니다.

var direction: UISwipeGestureRecoginzerDirection // which swipe directions you want 
var numberOfTouchesRequired: Int // finger count

 

UITapGestureRecognizer
Tap 제스처는 discrete 한 제스처입니다. 일반적으로 .ended 상태에서 어떤 동작을 수행할지 설정합니다. 그리고 몇개의 손가락으로 터치하는 제스처인지도 설정할 수 있습니다.

var numberOfTapsRequired: Int // single tap, double tap, etc.
var numberOfTouchesRequired: Int // finger count

 

UIPanGestureRecognizer
최대, 최소 손가락 개수를 선택할 수 있습니다. 

var maximumNumberOfTouches: Int
var minimumNumberOfTouches: Int

 

UIScreenEdgePanGestureRecognizer
Discrete 제스처입니다. 기기 스크린의 테두리에서 시작하는 panning 제스처를 인식합니다. 어느 모서리에서 인식하는지 선택할 수 있습니다. 추가로 각 모서리마다 새로운 UIScreenEdgePanGestureRecognizer를 등록해줘야합니다.

var edges: UIRectEdge

var leftEdge = UIScreenEdgePanGestureRecognizer(target: self, action: Selector("handleLeftEdgeGesture:"))
var rightEdge = UIScreenEdgePanGestureRecognizer(target: self, action: Selector("handleRightEdgeGesture:"))

leftEdge.edges = UIRectEdge.Left
rightEdge.edges = UIRectEdge.Right

self.view.gestureRecognizers = [leftEdge, rightEdge]

 

UILongPressRecognizer
Continuous 제스처입니다. 누른 상태에서 손가락을 움직일 경우 .changed 상태가 됩니다. 이 제스처는 .cancelled를 잘 다뤄야 한다고 합니다. 예를 들어 드래그 앤 드랍 기능을 구현할 때 드래그한 뷰가 목적지에 도달하지 못하고 제스처가 종료된다면 .ended가 아닌 .cancelled로 처리되어야 하는 경우가 생기기 때문입니다.

var minimumPressDuration: TimeInterval // how long to hold before its recognized 
var numberOfTouchesRequired: Int // finger count
var allowableMovement: CGFloat // how far finger can move and still recognize



데모

Swipe 제스처를 데모로 구현한 모습입니다. swipe 변수에 여러개의 방향을 리스트 형태로 넣어줄 수도 있고, 하나만 넣고 싶으면 "swipe.direction = .left" 이런식의 구현도 가능합니다. iOS가 IBOutlet을 playingCardView에 런타임에 전달할 때 didSet을 통해 UISwipeGestureRecognizer가 설정됩니다.
제 생각으로는 UI가 완전히 그려지기 전에 GestureRecognizer를 붙일 필요가 없기 때문에 didSet에서 설정해준 것 같습니다..🤔 (아니라면 언제나 댓글 환영입니다!)

@IBOutlet weak var playingCardView: PlayingCardView! {
    didSet {
        let swipe = UISwipeGestureRecognizer(target: self, action: #selector(nextCard))
        swipe.direction = [.left, .right]
        playingCardView.addGestureRecognizer(swipe)
    }
}

Swipe gesture

 

참고자료