연습/swift개발

4.11 얼굴에 제스처를 적용해보자

TimeSave 2022. 1. 20. 22:10

 

이제 데모를 통해서 이런 움직임 등을 어떻게 구현할 지 보자

제일 먼저 핀치 제스처(pinch gesture)를 만들어볼꺼야

우리 얼굴을 크거나 작게 조절해 줄 녀석이지

손가락으로 오므렸다 펴면서 이미지 스케일을 조정해 줄 거야

그 다음엔 팬 제스처(pan gesture)를 만들건데

차라리 스와이프 제스처(swipe gesture)로 하는게 낫겠다

이걸로 우리가 만든 모델(Model)을 바꿀거야

스와이프 제스처로 모델을 웃거나 슬픈 표정을 만들어 줄거야

표정을 웃거나 슬프게 하면 FaceView에도 적용돼서 보일거야

그럼 그렇게 해보자

FaceIt 프로젝트로 다시 돌아와서

어떻게 시작하면 될까?

우선 우린 Gesture Recognizer를 추가해야 해

전에 말했듯 faceView의 didSet안이 이것을 하기 좋다고 했어

여기 공간을 좀 넓혀볼게

하나만 있을 게 아니라 코드를 좀 더 추가해야 하니까

계속 여기서 updateUI( )를 해주겠지만

여기에 Gesture Recognizer(제스쳐 인식기)도 추가해 줄거야

여기 didSet은 단 한번만 호출될 것을 알고있긴 하지만

내 Outlet이 처음으로 UI에 연결될 때 한 번 호출되는 건 괜찮아

Gesture Recognizer는 한번만 추가되길 원하니까

faceView가 제스쳐를 인식해야 하는 걸 알고 있어

오직 view만 제스쳐를 인식할 수 있거든

그래서 faceView에 Gesture Recognize를 추가할거야

여기 보이듯이 Gesture Recognize를 추가하면

gesture recognize 인자를 받아

그럼 여기에 하나 만들지 뭐

UIPinchGestureRecognizer 를 만들거야

이 reconizer는 target과 action 두 개 인자를 받는군

여기 target에는 이 경우엔

핀치가 view의 스케일만 바꾸고

내 모델은 바꾸지 않기때문에

faceView 자신이 이걸 다루도록 할거야

faceView가 이걸 다룰려면

내 컨트롤러에 쓸 수 있는 제스쳐핸들러를 만들어야 할거야

public 메소드를 하나 만들어서 pinch를 다루도록 할거야

그래서 그 메소드를 faceView에 추가하는게 다음 할 일이야

여기 action은 셀렉터(selector)가 들어갈거야

faceView의 selector가 되겠지

메소드이름은 changeScale(비율바꾸기)이라고 할래

이 메소드엔 인자가 반드시 있어야할테니까

그 부분도 해주고

이렇게 해주면 좀 보기 쉽겠지

여기 에러가 하나 뜨는데

당연하게도 이 메소드를 아직 만들지 않았으니까

이 메소드가 진짜 있는지 확인하기에 좋은 에러이지

그럼 여기에 바로 이 메소드를 추가해보자

핀치가 발생했을 때 그것을 다룰 메소드가 될테니까

이 메소드를 faceView안에 만들어줄거야

FaceView로 가서

public으로 만들꺼니까 여기 위에가 좋을거야

이 메소드는 public으로 선언되어야 해

컨트롤러는 제스쳐핸들러가 이 메소드를 호출하길 원하니까

메소드 이름은 changeScale 이고

recongizer를 인자로 가지고 있을거야

UIPinchGestrueRecognizer 타입이겠지

제스쳐를 다루도록 요청받았을 때

recognizer가 우리에게 전달되어 오면 좋잖아

이 메소드가 처리할 일은 매우 간단해

인자로 넘어온 recognizer의 state(상태)로 switch문을 만들자

이 state가 Changed(변했다면)라면

아니면 Ended(끝났다면)라면

스위프트의 스위치문에선 이렇게 할 수 있어

여러 조건을 함께 적을 수 있는 것이지

Changed나 Ended라면

내 scale값에 recognizer의 scale값만큼 곱해줄거야

왜냐하면 여기 내 scale이 있는데

핀치가 2.0 즉, 두배 크기가 되면

scale값이 원래 scale 값의 두 배가 되도록 할거거든

0.5로 작아지면 원래 크기의 0.5 배가 되었으면 할거니까

하지만 이건 핀치가 움직여지면서 반복적으로 불릴거니까

여기서 한가지 확인해봐야 할 건

recognizer의 scale을 재설정 했는지야

항상 1.0이 되도록 말이지

scale이 움직이면 스케일 확장이나 축소를 점점 증가하게 할거야

왜냐하면 지금은 scale의 변화에 대해 적용하고 있는 거니까

매번 scale이 움직일 때마다 즉 .Changed에 해당 될 때마다

난 scale에 적용할거야

물론 우리는 default 상태도 있어야겠지

cancel(취소)이나 begin(시작)같은 것들 말이야

그런 모든 경우에는 난 아무것도 하지 않을거야

난 scale이 움직이는대로 scale을 추적하고 실행하는 것이니까

나한테 그 움직임이 언제 끝날지는 상관이 없어

내 말은 scale을 마지막으로 조정하는 부분을 위해

손가락을 올리게 하는 것도 꽤 괜찮을 수 있겠지만

그렇게 중요한 건 아니야

cancel이 되면 어쨌든 그런 기회도 얻지 못하겠지

모두들 이해하겠니?

이건 public 메소드이고

거기 질문 있니?

(질문 중..)

여러번 말했지만 모두들 의아할 수 있는 부분인데

이렇게 하는 이유는 내가 이렇게 하지 않으면

핀치를 하면 scale이 계속 누적되고 말거야

여기서 시작했다고 해보자

여기서 핀치로 점점 더 크게 해볼거야

그때마다 scale을 바꾸라는 메소드가 계속 호출되겠지

처음엔 1.0이었다가 1.1, 1.2, 1.3....2.0 이렇게 계속 늘거야

핀치를 조정하는만큼 계속 불리겠지

scale을 가져와서 1.0, 1.1, 1.2, 1.3을 계속 곱한다고 생각해봐

scale이 엄청나게 커져버릴거야

그건 내가 원하는게 아니지

내가 원하는 건 원래 scale에서 증가시키는 거야

scale을 다시 1로 설정되도록 해두면

조금 커지면 1.1이 되었다가

다시 1로 설정하고 이게 1.1이 되는 구조가 되겠지

다른 방법은 손가락을 뗄 때까지는

핀치가 아무것도 하지 못하도록 하다가 손을 떼면 그제서야

scale을 설정하도록 할 수도 있겠지

하지만 지금은 원래 scale에 더하는 형태로 하고 있으니까

매번 1.0이 되도록 설정하는 거야

좋은 질문이었어

이제 FaveViewController로 다시 돌아가면

이제 이 코드라인에 에러가 생기지 않지

이 핸들러(handler)를 정의해주었으니까

이제 한번 작동해보자

핀치를 하면 얼굴의 scale값이 업데이트되어야 할텐데 말야

여기 우리 얼굴이 있는데 별로 행복해 보이진 않군

얼굴을 좀 작게 만들어서 티가 나지 않도록 해볼거야

너흰 마우스로 어떻게 pinch를 할지 궁금할지도 몰라

마우스가 있긴 한데 이걸로 어떻게 핀치를 할까 하는거지

옵션 키(alt)를 사용하면 돼

시뮬레이터를 작동시키고 옵션 키를 누르고 있으면

이렇게 손가락 두개가 나타나

이 상태에서 마우스를 움직이면 핀치하는 것처럼 움직일거야

이렇게 핀치로 확대하거나 축소할 수 있어

됐지?

제스쳐 조작하기 매우 간단한게 보이지

이걸 하는데 코드 4줄 정도면 됐지

핀치말고 다른 Gesture Recognizer도 만들어보자

모델을 바꾸는 것을 만들어보자

여기서 내가 할 건 이렇게 아래로 쓸어내리면

슬픈 얼굴이 되고 쓸어올리면 행복한 얼굴이 되게 할거야

모델을 바꿔서 말야

모델을 바꿔서 행복하게 보이도록 만드는거지

내 입의 곡률(굽은 정도)을 움직이는게 아니라

모델을 바꿀거야

물론 모델을 사용할 때마다 내 입의 곡률을 바꿔줄거고

그렇게 작동이 될거야

우리가 할 건 모델을 바꾸는 일이지

그렇게 하려면 Swipe(쓸어내기) Gesture를 만들어야 해

Swipe Gesture를 우리가 설정해줘야 하는데

지역변수를 하나 만들어 Swipe Gesture를 가지고 있을건데

지역변수 이름은 happierSwipeGestureRecognizer 로 할게

그리고 여기에 UISwipeGestureRecognizer

전처럼 똑같이 target과 action를 인자로 받는 걸 쓸거야

여기 target은 faceView가 되진 않을거야

모델을 바꿀것이기 때문이야

대신 self(자기자신)가 될거야

컨트롤러가 이걸 다루도록 해야겠지

action에는 셀렉터(selector)형식이 되어서

faceView가 아니라 FaceViewController셀렉터가 들어올거야

여기에 들어올 함수를 뭐라고 부를거냐면

손으로 쓸어올리면 행복한 표정을 짓게 만들거니까

increaseHappiness(행복 늘리기)라고 할거야

이 함수에서 Swipe Gesture를 받을 필요가 없지

왜냐하면 인지가 될 수도 있고 안 될 수도 있으니까

그래서 저 increaseHappiness 메소드엔 아무 인자도 없는거야

이 함수도 전에 한 것처럼 깔끔하게 보이게 정리할게

여기 있는 메소드는 인자가 전혀 없을거야

그럼 이제 func로 시작하는 저 함수를 정의해주어야겠지

increaseHappiness에 인자는 없고

increaseHappiness가 호출되면 모델에 무엇을 해주어야 할까

얼굴 expression의 mouth에

expression.mouth.happierMouth( )를 할당해줄거야

여기 있는 FacialExpression으로 가보면

enum으로 선언되어 있는 Mouth에는 메소드 2개가 있어

sadderMouth( )와 happierMouth( ) 인데

현재 mouth상태를 받아서 슬프거나 행복한 입으로 만든 다음에

새로운 mouth를 반환하는 함수들이야

여기 있는 case에 따라 웃는 정도를 설정할 수 있어

Mouth가 어떻게 되어 있는지 알았으니까

이렇게 하면 괜찮을거고

이 SwipeGesture는 view에 더해주어야 해

addGestureRecognizer로 더해주어야 하는데 아직 안했지

또 그에 대한 환경을 설정해주어야 하지

설정을 할건데 이건 웃음을 짓는 모양이니까

이 swipeGestureReconizer의 direction(방향)을

그러니까 쓸어넘기는 방향을

.Up(위)라고 설정할거야

위쪽으로 쓸어올리면 웃는 얼굴을 지을거야

그리고 두 손가락이 아니라 한 손가락으로 쓸어넘기게 될거야

그럼 이제 faceView에 addGestureRecognizer를 하고

여기에 happierSwipeGestureRecognizer를 넣어줄거야

이해되니?

그럼 한번 이 상태로 실행해보자

우리가 여기 있는 얼굴의 표정을 바꿀 때마다

여기 didSet이 있으니까 자동으로 UI를 업데이트 해줄거야

여기 보듯이 expression부분이 바뀌면 짠하고 UI가 업데이트 돼

그럼 한번 해보자

핀치를 하면 아까처럼 작동이 되어야 할텐데 잘 되는군

이번엔 위로 쓸어올려보면 점점 더 행복한 미소를 짓고 있지

하지만 이번엔 아래로도 쓸어내리고 싶어졌어

지금은 쓸어올릴 수만 있으니까 쓸어내릴 수도 있도록 해보자

이거랑 거의 똑같은 코드니까 복사 붙여넣기해서 해보자

다만 happier부분을 sadder라고만 바꿔줄거야

또 이번엔 Up으로 쓸어내는게 아니라 Down이 되야겠지

그리고 increaseHappiness(행복을 늘리기)대신에

decreaseHappiness(행복을 줄이기)를 써야 할거야

그럼 decreaseHappiness라는 새 메소드를 만들어야겠지

이 부분에서는 sadderMouth( ) 가 실행되어야겠지

모두들 잘 이해해야 할 흐름이 있는데

컨트롤러에 의해 다뤄지는 핸들러로 움직이는

Recognize(인식기)가 있다는 거야

그리고 컨트롤러는 모델을 고치지

모델이 수정될 때마다 여기 있는 updateUI( )를 호출할테고

updateUI( )는 여기에선 입의 곡률을 업데이트하는 일을 하겠지

모두들 이 흐름이 이해되니?

이제 쓸어내리는(Swipe Down)게 잘 동작하는지 확인해보자

쓸어내리면 슬픈 얼굴이 되고, 쓸어올리면 행복한 얼굴이 되지

슬프거나 행복하거나... 이해되겠지?

제스처 하나만 더 해보자

탭(tap)하면 눈을 뜨거나 감거나 할거야

탭할 때마다 눈 감고 뜨는걸 스위치처럼 키고 끌거야

근데 이건 약간 다르게 할건데

지금까진 모든 GestureRecognizer를 여기 코드에 추가했었지

코드에 이렇게 GestureRecognizer를 추가한게 보이지

근데 사실 이것들을 스토리보드에서도 추가해 줄 수 있어

그럼 여기 스토리보드로 한 번 가보자

컨트롤러와 스토리보드가 함께 보이도록 해보자

이걸 자동(Automatic)으로 두면 돼

여기엔 컨트롤러가 있고 여기엔 FaceView가 보이지

스토리보드에서 여기 있는 FaceView에 제스쳐를 추가하려면

여기 아래쪽에 버튼 같은 것을 가져오곤 했던 같은 곳으로 가서

스크롤을 쭈욱 내려보면 GestureRecognizer가 있어

Rotation, Pinch, Swipe, Pan 가 있는데

여기 Tap을 밖으로 꺼내서

탭이 인식되기를 원하는 뷰로 control 키 + 드래그 해올거야

여기선 FaceView가 되겠지

이렇게 하면 여기 위에 뭔가가 표시가 되지

여기 TapGestureRecognizer가 들어와 있는게 보이지?

이쪽으로 와서 세부 설정을 할 수도 있어

탭을 몇 번해야 인식할지 터치를 몇 번해야 인식할지를 말야

몇개 손가락으로 탭할지도

이 버튼에서 여기로 control 키 + 드래그해 올 수도 있지

좀더 아래쪽으로 내려가서

바로 여기에 GestureRecognizer Action이 새로 만들어져

이름은 toggleEyes(눈 온오프 스위치)라고 부를거고

인자는 AnyObject가 아니라 UITapGestureRecognizer야

이 작은 창에서 AnyObject를 다른 걸로 바꿔주는 건 알고 있지

그럼 여기에 탭 제스쳐가 있고

이제 하나만 보이도록 전체 화면으로 돌아가보자

여기엔 toggleEyes라고 불리는 탭 제스쳐가 있고

이제 여기서 내 눈을 감거나 뜨게 해야하니까

만약 recognizer의 state(상태)가 Ended이면

탭이 끝났으면

이제 어떤 행동을 할거고 스위츠를 온-오프할 건지를 적어야지

현재 눈의 상태에 따라

눈을 뜨고 있다면 expression의 eyes를 감게 만들거고

눈을 감고 있다면 expression의 eyes를 뜨게 만들겠지

눈을 가늘고 길게 뜨고 있다면 아무것도 하지 않을거야

왜냐하면 가늘고 길게 뜨는 눈은 어떻게 해줄지 모르겠거든

이해되니?

미안, 실수가 하나 있어

여기에 recognizer.state 라고 한 것 보이지

ctrl + 드래그 하면 기본값으로 sender라고 이름을 붙이는데

이걸 recognizer라고 수정할거야

여기서 사용하는 건 recognizer라는 이름을 가진 녀석이니까

Gesture를 인식하는 'recognizer' 말이야

이렇게 해서 실행해보자

좋아, 여기 얼굴이 있고

쓸어내려서 웃게 만들수도 있고

탭해서 눈을 감고 뜨게 할 수도 있지

나중 수업에서는 애니메이션에 대해 알아볼건데

눈에 애니메이션 효과를 줘서 알아서 깜빡이도록 할 수도 있겠지

수업 끝나면 오늘 실습한 코드를 올려줄건데

다음에 할 것도 들어있을거야

눈썹을 움직이기위해 회전시키는 방법을 보여줄건데

눈썹이 위쪽으로 회전하거나 아래쪽으로 회전하게 할거니까

회전은 어떻게 하는건지 알려줄게

그건 내가 올릴 코드에 들어있을거야

제스쳐에 대해 뭐든 질문이 있니?

매우 직관적이지

그럼 슬라이드로 다시 돌아오자

(질문 중)

질문이 뭐였냐면

새롭게 만든 Gesture Recognizer를 추가하는 코드가 없어도

(스토리보드로 하면) UIView에 자동으로 추가되느냐는 거였어

학생이 물어보는게 addGestureRecognizer가 불리냐는거지?

물론이지

기본적으로 탭 제스쳐를 FaceView로 드래그 해오면

addGestureRecognizer가 자동으로 호출된다고 보면 돼

알겠니?