Swift - Gestures

이원석·2025년 1월 6일

Swift

목록 보기
38/38

Gestures

제스처는 화면을 통해 전달된 사용자의 입력

UIGestureRecognizer

GestureRecognizer는 제스처 인식기라고도 하며 여러 터치 이벤트를 인식. 특정 제스처 이벤트가 일어나면 각 타겟에 맞는 액션 메시지를 보내 제스처 관련 이벤트를 처리.

  • UIGestureRecognizer
    UIGestureRecognizer 클래스는 이런 Gesture Recognizer가 구성되어야 하는 공통의 동작 세트를 정의. 여러 하위클래스들은 다양한 제스처를 인식하고 처리.
    제스처는 iOS에서 UIGestureRecognizer 클래스의 인스턴스에 의해 인식.
    UIGestureRecognizer는 추상적. UIGestureRecognizer를 생성하지 않고 UIGestureRecognizer를 상속받는 클래스를 사용

Recognizer 클래스 사용단계

  • Recognizer 클래스를 사용할 때 2가지 단계
  1. 어떤 UIView객체가 이 Recognizer를 받아서 해당하는 제스처를 인식할 수 있도록 설정(제스처를 인식하는 파트)
    -> GestureRecognizer를 생성하면 인식(View에게 이 GestureRecognizer를 사용하라고 요청)(오직 View만 제스처를 인식할 수 있고 Controller는 불가능)

  2. 그 Recognizer가 제스처를 인식햇을 때 처리(GestureHandler가 담당)
    GestureHandler는 GestureRecognizer가 해당하는 제스처를 인식하는 상태기계로 갈때 호출 됨
    GestureRecognizer를 생성하고 View에 추가하는건 일반적으로 Contoller가 처리(어떤 View들은 자체적으로 GestureRecognizer를 추가 ex.. ScrollView)

    Controller는 제스처를 인식할 수 없음. 오직 GestureRecognizer를 가지고 있는 View만 가능

    Handler는 Controller에서 처리할 수도 있고, View에서 처리할 수도 있음. 아예 다른 곳에서 처리할 수도 있지만 UI와 독립된 구조이기 때문에 모델에서 처리할 일은 없음.

상태기계
상태기계는 한 번에 하나의 상태를 가지고, 어떤 이벤트에 의해서 다른 상태로 전이 된다.

서브클래스

UITapGestureRecognizer

탭 체스처 인식
.Ended로 탭동작이 끝났는지 확인
var numberOfTapsRequired: Int//탭 횟수
var numberOfTouchesRequired: Int//손가락 개수
1. 스토리 보드에서 추가하기

  • shift + command + L 에서 Tap Gesuture Recognizer선택 후 드래그하여 추가(탭 횟수나 손가락 개수는 attributes inspector에서 설정)
  • Tap Gesture Recognizer를 control + 드래그하여 controller와 연결 후 동작 설정
@IBAction func toggleEyes(_ recognizer: UITapGestureRecognizer) {
        if recognizer.state == .ended{
            switch expression.eyes{
            case .Open : expression.eyes = .Closed
            case .Closed : expression.eyes = .Open
            case .Squinting : break
            }
        }
    }
  1. 코드에서 추가하기
  • UIView객체에 Recognizer를 추가하여 제스처를 인식할 수 있도록 설정
//FaceViewController 클래스
@IBOutlet weak var faceView: FaceView! {
        didSet {// 처음 뷰가 연결이 될 때 호출
            let blinkEyesTapGestureRecognizer = UITapGestureRecognizer(
            	target: self, action: #selector(FaceViewController.blinkEyes)
            )//target은 FaceViewController이므로 self(FaceViewController안에 faceView와 blinkEyes존재)
            
            faceView.addGestureRecognizer(blinkEyesTapGestureRecognizer)
            
            updateUI()// MVC가 생성된 직후에 iOS가 나타나고 이 outlet이 연결될때 호출
        }
    }
  • Recognizer가 제스처를 인식햇을 때 처리추가
//FaceViewController 클래스
    @objc func blinkEyes(){
        if expression.eyes == .Open {
            expression.eyes = .Closed
        }else {
            expression.eyes = .Open
        }
    }

UIPinchGestureRecognizer

핀치(두 손가락을 벌리거나 좁히는) 제스처 인식
var scale: CGFloat //비율
var velocity: CGFloat { get }//핀치 속도

  1. 코드로 추가하기
  • UIView객체에 Recognizer를 추가하여 제스처를 인식할 수 있도록 설정
//FaceViewController클래스
@IBOutlet weak var faceView: FaceView! {
        didSet {// 처음 뷰가 연결이 될 때 호출
            faceView.addGestureRecognizer(UIPinchGestureRecognizer(
                target: faceView, action: #selector(FaceView.changeScale(_ : ))
            )) 
            
            updateUI()// MVC가 생성된 직후에 iOS가 나타나고 이 outlet이 연결될때 호출
        }
    }
  • Recognizer가 제스처를 인식햇을 때 처리추가
//FaceView 클래스
@objc func changeScale(_ recognizer: UIPinchGestureRecognizer){
        switch recognizer.state{
        case .changed, .ended:
            scale *= recognizer.scale
            recognizer.scale = 1.0
        default:
            break
        }
    }

UISwiperGestureRecognizer

스와이프 제스처 인식
사용전에 설정해야함(어느방향으로 쓸어내릴지, 손가락 몇 개로 할지)
var direction: UISwipeGestureRecognizerDirection
var numberOfTouchesRequired: Int
1. 코드로 구현

  • UIView객체에 Recognizer를 추가하여 제스처를 인식할 수 있도록 설정
//FaceViewController 클래스
@IBOutlet weak var faceView: FaceView! {
        didSet {// 처음 뷰가 연결이 될 때 호출
           let happierSwiperGestureRecognizer = UISwipeGestureRecognizer(
                target: self, action: #selector(FaceViewController.increaseHappiness)
            )
            
            let sadderSwipeGestureRecognizer = UISwipeGestureRecognizer(
            	target: self, action: #selector(FaceViewController.decreaseHappiness)
            )
            
            happierSwiperGestureRecognizer.direction = .up//위로 스와이프할 때
            faceView.addGestureRecognizer(happierSwiperGestureRecognizer)
            
            sadderSwipeGestureRecognizer.direction = .down//아래로 스와이프 할때
            faceView.addGestureRecognizer(sadderSwipeGestureRecognizer)
            
            updateUI()// MVC가 생성된 직후에 iOS가 나타나고 이 outlet이 연결될때 호출
        }
    }
  • Recognizer가 제스처를 인식햇을 때 처리추가
//FaceViewController 클래스
@objc func increaseHappiness(){
        expression.mouth = expression.mouth.happierMouth()
    }
    
    @objc func decreaseHappiness(){
        expression.mouth = expression.mouth.sadderMouth()
    }

UIRotationGestureRecognizer

회전 제스처 인식
var rotation: CGFloat// 몇 라디안만큼 회전했는지
var velocity: CGFloat { get }//회전 속도

UIPanGestureRecognizer

팬(드래그) 제스처 인식
func translationInView(UIView) -> CGPoint//view좌표에서 팬이 얼마나 움직였는지
func velocityInView(UIView) -> CGPoint//팬이 얼마나 빨리 진행되는지
func setTranslation(CGPoint, inView: UIView)//현재 뷰의 위치 설정
1. 코드로 구현하기

  • UIView객체에 Recognizer를 추가하여 제스처를 인식할 수 있도록 설정
@IBOutlet weak var pannableView: UIView {
	didSet{
    	let recognizer = UIPanGestureRecognizer(
        	target: self, action: #selector(ViewController.pan(_:))//Objective-c 런타임 호환 selector
        )
        pannableView.addGestureRecognizer(recognizer)
    }
}
  • Recognizer가 제스처를 인식햇을 때 처리추가
func pan(gesture: UIPanGestureRecognizer){
	switch gesture.state{
    case .Changed: fallthrough
    case .Ended:
    	let translation = gesture.translationInView(pannableView)
        //update anything that depends on the pan gesture using translation.x and .y
        gesture.setTranslation(CGPointZero, inView: pannableView)
     default: break;
    }
}

UIScreenEdgePanGestureRecognizer

화면 가장자리 팬 제스처 인식

UILongPressGestureRecognizer

길게 누르는 제스처 인식

UIHoverGestureRecognizer

호버(마우스나 펜 같은 포인터 장치를 사용할 때, 화면 위에서 움직이는) 제스처 인식


state

GestureRecognizerstate변수를 가지고 있음
var state: UIGestureRecognizerState { get } : 핸들러에서 제스처가 어떤 상태에 있는지 확인할 수 있음. 모든 GestureRecognizer는 .Possible상태에서 시작
스와이프인 경우 감지하면 바로 .Recognized로 상태가 바뀜(스와이프를 인식한 것)

팬이나 핀치같은 지속되는 제스처는 팬이 눌리는 순간부터 바로 .Began이라는 상태가 됨. 팬이 움직이는 순간부터 .Changed라는 상태로 바뀜. 핸들러도 .Changed의 상태가 될 때마다 반복적으로 호출.
손가락이 화면에서 뗴지면 .Ended상태로 가게 됨
추가적으로 .Failed, .Cancelled도 존재

@objc func handleSwipeRight(_ gestureRecognizer: UISwipeGestureRecognizer) {
    switch gestureRecognizer.state {
    case .possible:
        print("possible")
    case .began:
        print("began")
    case .changed:
        print("changed")
    case .ended:
        print("ended")
    case .cancelled:
        print("cancelled")
    case .failed:
        print("failed")
    case .recognized:
        print("recognized")
    @unknown default:
        fatalError()
    }
}

참조
go.log
권지수
민소네
김종권의 iOS 앱 개발 알아가기

0개의 댓글