[iOS] 스탠포드 CS193P 6강

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

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)
}
}


참고자료