제스처 인식기
Gesture Recognizer는 일련의 터치를 인식하고, 인식에 따라 동작하는 로직을 분리시킨다.
즉, 제스처를 인식하거나 제스처의 변경을 인식하면 연결된 target에 actoin메세지를 보낸다.
UIGestureRecognizer 클래스는 이런 Gesture Recognizer가 구성되어야하는 공통의 동작세트를 정의하고 있다.
View에 UIGestureRecognizer가 있다면 Window는 터치이벤트를 View에 전달하기 전에 UIGestureRecognizer객체에 먼저 전달하게 된다.
UIGestureRecognizer가 전달받은 터치 이벤트에서 특청 제스처로 인식한다면 UIGestureRecognizer가 이벤트를 처리하고 View로 전달된 터치이벤트를 취소하고, 나머지 터치이벤트도 전달하지 않는다.
cancelsTouchesInView
제스처가 인식됐을 때 뷰에 터치를 전달해 줄 것인가에 대한 Bool 값
이 값이 true(defalut)이고 리시버가 제스처를 인식하면, 제스처의 터치는 뷰에 전달되지 않고, touchesCancelled(_:with:)message가 뷰에 전달되고 이미 전달된 터치도 캔슬.
만약에 Gesture Recognizer가 제스처를 인식하지 못하거나, 이 값이 false이면 뷰는 모든 터치를 전달받음.
[삽질 방지] UIButton이 Tap Gesture를 인식 못하는 원인 5가지
addTarget과 addGestureRecognizer 차이
addTarget은 UIControl 객체만 적용할 수 있지만 addGestureRecognizer은 UIView 객체에 모두 적용가능하다.
Subclass
기본적으로 정의되어있는 subClass는 7개가 존재
단순 제스처를 인식하는 것은 Discrete, 제스처의 변경을 인식하고자 하면 Continuous를 사용
Discrete
- UITapGestureRecognizer
- UISwipeGestureRecognizer
Continuous
- UIPinchGestureRecognizer
- UIRotationGestureRecognizer
- UIPanGestureRecognizer
- UIScreenEdgePanGestureRecognizer
- UILongPressGestureRecognizer
UIPanGestureRecognizeer
panning gesture를 해석하는 연속 제스처 인식기이다.
UIPanGestrueRecognizer은 UIGestrueRecognizer의 구체적인 하위 클래스이다.
이 클래스의 클라이언트는 액션 메서드에서 UIPanGestureRecognizer 객체에 제스처의 현재 변환(translation(in:))과 변환의 속도(velocity(in:))를 쿼리할 수 있고, 변환과 속도 값에 사용할 뷰의 좌표계를 지정할 수 있다.
클라이언트는 원하는 값으로 변환을 재설정할 수도 있다.
panning gesture는 연속적이다. 사용자는 뷰를 panning하는 동안, 하나 이상의 손가락을 뷰에 눌러야 한다. 사용자가 팬으로 인식할 수 있는 충분한 거리만큼 허용된 최소 손가락 수(minimumNumverOfTouches)를 움직이면 제스처가 시작된다.(UIGetstureRecognizer.State.began)
사용자가 최소 손가락 수로 누른 상태에서 손가락을 움직이면 UIGestureRecognizer.changed상태로 변경된다. 사용자가 모든 손가락을 들어올리면, 종료(UIGetstureRecognizer.ended)된다.
Handle UIPanGestureRecognizer
팬 제스처는 사람이 하나 또는 더 많은 손가락들을 스크린주변에 움직일때마다 발생한다. 스크린 엣지 팬 제스처는 화면의 가장자리에서 시작하는 특수한 팬 제스처이다. 팬 제스처에는 UIPanGestureRecognizer클래스를 사용하고 엣지팬제스처에는 UIScreenEdgePanGestureRecognizer 클래스를 사용한다.
아래 방법들로 제스처 인식기를 붙일 수 있다.
- 해당 뷰의 addGestureRecognizer(_:)메서드를 호출한다.
- Interface Builder안, 라이브러리로부터 해당객체를 끌어다 해당뷰위에 놓는다.
화면에서 사용자 손가락의 움직임을 추적해야하는 작업에는 팬 제스처 인식기를 사용한다. 팬 제스처 인식기를 사용하여 인터페이스에서 물체를 드래그하거나 사용자 손가락의 위치를 기반으로 포지션을 업데이트할 수 있다.
팬 제스처는 연속적이므로, 터치정보가 변경될 때마다 액션메서드가 호출되어 콘텐츠를 업데이트할 수 있다.
팬 제스처 인식기는 필요한 양의 초기 이동이 이루어지자마자 UIGestureRecognizer.State.began 상태로 들어간다.해당 초기 변경 후, 이후 변경은 제스처 인식기가 UIGestureRecognizer.State.changed상태로 들어간다.
사용자의 손가락이 화면으로부터 들어올려졌을 때, 제스처 인식기는 UIGestureRecognizer.State.ended 상태로 들어간다.
추적을 단순화하기위해, 제스처 인식기의 translation(in:)메서드를 사용하여 사용자의 손가락이 원래 터치 위치로부터 이동한 거리를 얻는다. 제스처를 시작할 때, 팬 제스처 인식기는 사용자의 손가락들에 대한 초기 접촉 포인트를 저장한다. (제스처가 여러 손가락들을 포함하는 경우, 제스처 인식기는 터치들의 세트의 중심점을 사용한다.) 손가락들이 움직일 때마다, translation(in:)메서드는 원래 위치로부터의 거리를 보고한다.
아래 코드는 화면 주위로 뷰를 드래그하는데 사용된 액션메서드를 보여준다. 제스처를 시작할 때, 이 메서드는 그 뷰의 초기 포지션을 저장한다. 그런 다음에, 사람의 손가락의 움직임을 기반으로 뷰의 포지션을 업데이트 한다.
var initialCenter = CGPoint() // The initial center point of the view.
@IBAction func panPiece(_ gestureRecognizer : UIPanGestureRecognizer) {
guard gestureRecognizer.view != nil else {return}
let piece = gestureRecognizer.view!
let translation = gestureRecognizer.translation(in: piece.superview) //슈퍼뷰의 좌표공간에 대한 x방향과 y방향의 변화를 가져온다.
if gestureRecognizer.state == .began {
// Save the view's original position.
self.initialCenter = piece.center
}
// Update the position for the .began, .changed, and .ended states
if gestureRecognizer.state != .cancelled {
// Add the X and Y translation to the view's original position.
let newCenter = CGPoint(x: initialCenter.x + translation.x, y: initialCenter.y + translation.y)
piece.center = newCenter
}
else {
// On cancellation, return the piece to its original location.
piece.center = initialCenter
}
}
팬 제스처 인식기의 코드가 호출되지 않는 경우, 다음 조건이 사실인지 확인하고 필요에 따라 수정한다.
- 뷰의 isUserInterationEnabled 속성은 true로 설정된다. 이미지뷰와 label들은 이 속성을 기본적으로 false로 설정한다.
- 터치 횟수는 minimumNumberOfTouches속성과, maximumNumberOfTouches속성에 지정된 값 사이이다.
- UIScreenEdgePanGestureRecognizer객체의 경우, 엣지 속성이 구성되고, 터치들이 적절한 엣지에서 시작된다.
- 속성
- var maximumNumberOfTouches: Int
- 제스처 인식을 위해 뷰를 터치할 수 있는 최대 손가락 수.
- var minimumNumberOfTouches: Int
- 제스처 인식을 위해 뷰를 터치할 수 있는 최소 손가락 수
- var maximumNumberOfTouches: Int
- 메서드
- func translation(in: UIView?) → CGPoint
- 지정된 뷰의 좌표계에서 팬 제스처를 해석한다.
- 파라미터
- view : 팬 제스처의 변환이 계산되어야 하는 좌표계의 뷰이다. 뷰의 위치를 조정하여 사용자의 손가락 아래에 유지하려면 해당 뷰의 슈퍼뷰의 좌표계에서 변환을 요청한다.
- 리턴 값
- 지정된 슈퍼뷰의 좌표계에서 뷰의 새 위치를 식별하는 point이다.’
- 주의
- x및 y값은 시간 경과에 따른 총 변환을 보고한다. 이는 변환이 보고된 마지막 시간의 델타값이 아니다.
- 제스처가 처음 인식될 때, 변환값을 뷰의 상태에 적용한다. 핸들러가 호출될 때마다 값을 연결하지 마라.
- func setTranslation(_: CGPoint, in: UIView?)
- 지정된 뷰의 좌표계에서 변환 값을 설정한다.
- 파라미터
- translation
- 새로운 변환값을 식별하는 지점
- view
- 변환이 발생할 좌표계의 뷰
- 주의
- 변환값을 변경하는것은 팬의 속도를 재 설정한다.
- translation
- func velocity(in: UIVIew?) → CGPoint
- 지정된 뷰의 좌표계에서 팬 제스처의 속도를 해석한다.
- 파라미터
- view: 팬 제스처의 속도를 계산하는 좌표계의 뷰이다.
- 리턴값
- 팬 제스처의 속도는 초당 포인트로 표시된다. 속도는 수평 및 수직 구성요소로 나뉜다.
- 파라미터
- 지정된 뷰의 좌표계에서 팬 제스처의 속도를 해석한다.
- func translation(in: UIView?) → CGPoint
Pan 제스처는 Drag와 비슷한 개념
View를 Panning하기 위해서는 하나 이상의 손가락이 필요함, 최소 하나 이상이기 때문에 설정에 따라 2,3 개 손가락도 가능함
Pan제스처로 인식되기 위해서는 설정된 최소 손가락수로 설정된 최소거리는 움직여야 함
minimumNumberOfTouches, maxmumNumberOfTouch로 각각 최소 손가락 수, 최대 손가락 수를 설정할 수 있다.
began 상태에서 손가락을 움직일 때마다 changed로 변경이 되고, 손을 떼면 ended로 변경된다.
- Pan 제스처 인식조건
- began : 설정된 손가락 수로 설정된 거리를 이동한 시점
- changed: began 이후 손가락을 움직일때마다
- ended: 손을 뗀 시점
- state가 began으로 설정될 때의 터치위치를 저장하기 때문에 이후 translation(in:)메서드에서 저장된 원래위치로부터 거리를 얻을 수 있음
translation(in:)메서드는 CGPoint타입을 반환하는데, 이때 x,y값을 사용하여 이동한 거리를 구해 contents를 이동할 수 있다.
중요한것은 꼭 setTranslation(:, in:)메서드를 사용하여야하는데, 이때 translation(.zero, in: recognizerView)를 해주어야한다.
왜 zero로 해주냐면, PanGestureRecognizer의 translation값은 이전 값에서 얼마나 떨어졌는 지가 아니라, state began단계일 때의 점, 즉 원점에서 얼마나 떨어졌는지를 나타내는 값이기 때문임.
움직이고자하는 View를 포함한 contents에 이 translation값을 사용하여 변화를 주었다면, 그 시점에서 변화된 contents의 translation을 0으로 주어, 즉 이 지점이 새로운 원점임을 알려주어야 의도대로 이동할 수 있다.
'개발일기 > IOS' 카테고리의 다른 글
[IOS] - 기초 공부 (0) | 2024.03.15 |
---|---|
[Swift] - Notification 정리 (0) | 2024.03.15 |
[Swift] - View의 Cycle (0) | 2024.03.15 |
[Swift] - Animation 정리 2 (0) | 2024.03.15 |
[Swift] - Animation 정리 1 (0) | 2024.03.15 |