본문 바로가기
iOS/SwiftUI

#10 Gestures

by HaningYa 2020. 10. 22.
728x90

모바일 앱의 UI를 개발하는데 있어 동적인 요소들은 시각적으로 부드럽게 화면이 업데이트되는 경험을 줄 수 있다.
이번 챕터에서는 제스쳐와 같은  user interaction이 어떻게 추가되고 합쳐지고 custom 하게 전달되서 특별한 사용자 경험을 줄 수 있을 지에 대해서 알아본다.
Kuchi 앱에서 탭바를 추가해 새로운 단어를 배우는 화면을 추가할 것 이다.

Adding learn feature

두개의 탭으로 구성된 탭바를 만들 것 이다.

  • 배우는 화면 (이번에 만들 것이다)
  • 기존 challenge 화면

먼저 배우는 기능을 할 최상위 empty view 를 만들어 준다. 
여러개의 파일로 구성될 것인데 Learn group으로 묶어준다.(practice folder 와 같은 level 에 위치한다.)

그리고 탭바를 host할 HomeView.swift 를 만든다.
body 에TabView 를 만든다.

tag(0) 을 통해 해당 tab 의 index 를 정하고 VStack으로 탭에 표시될 아이콘과 텍스트를 묶고 tabItem 에 넣어준다.
LearnView는 탭이 선택됬을 때 보여지는 view 이다.

두번째 탭을 추가해 주려면 먼저 리팩토링이 필요하다.
WelcomeView에서 PracticeView 를 방금만든 HomeView 로 바꿔줘야 한다.
그리고 PracticeView 를 HomeView 의 2번째 탭으로 넣어준다.

Creating a flashcard

Learn 탭에서 flash card 를 만들 것 이다.
보여지는 카드 (UI component) 와  카드 데이터 (state) 가 필요하다.

카드 UI 는 state 없이는 존재할 수 없기 때문에 state 를 표현할 수 있는 데이터 구조가 필요하다.

  • 표시할 단어를 가지는 Challenge type card 변수이다.
  • 여러장의 카드를 view에서 iterating 할 거기 때문에 Identifiable protocol 을 준수하는게 좋다. 
    예를들어 ForEach SwiftUI block 같은 경우 id 가 필요하다.
  • id 만드는 로직이 없으니 Foundation 의 UUID 메서드를 사용한다.
  • filtering 을 위해 isActive 를 추가한다.
  • Equatable 을 통해 비교 가능하게 만든다. (== 오퍼레이터 쓸 수 있게)

사용자는 카드 한장씩 공부하지 않을 것이기 때문에 카드 배열을 담을 수 있는 deck 같은 개념이 필요하다.

Building flash deck

  • Flashcard의 배열인 cards 를 가지게 한다.
  • 덱에 따라 UI 가 변하게 하기 위해 @published 로 선언하고 class 도 ObservableObject로 선언한다.

Final state

deck 을 가지고 있어 사용자가 deck 을 관리하고 UI 업데이트를 받을 수 있는 최상단 저장공간이 필요하다.
LearningStore 파일을 만든다.

And finally... building the UI

UI 는 3단계로 구성된다.

LearnView와 그 위의 deckView 와 그 위의 cardView 이다.
CardView.swift 부터 만들어 보자

다음 DeckView 를 만들자

다시 LearnView로 돌아가서 뷰 수정한다.

 

Adding LearningStore to the views

과정 생략..

Your first gesture

SwiftUI 의 제스쳐는 AppKit과 UIKit 과 비슷하지만 더 간단하다.
눙력은 비슷하지만 SwiftUI 는 더 쉽게 제스쳐를 만들 수 있다.

TapGesture

CardView 에서 Tap 해야 정답을 보여주는 기능을 만들어 본다.

 

Custom gestures

drag gesture 을 통해 사용자가 외운 단어인지 판단하는 기능을 만들어 본다.

DeckView.swift에서 방향을 나타내는 enum 을 만든다.

그리고 CardView에서 카드를 draggable 하게 만든다.

dragged 프로퍼티는 카드를 드래그 될 수 있게 해주고 어느 방향으로 드래그 됬는지 enum 결과를 반환해준다.
다음 init 에 dragged closure 를 파라미터로 받아준다.

다음 DeckView 에서 카드의 새로운 기능을 지원할 수 있도록 만들어 준다.

마지막 단계는 실제 drag 제스쳐를 적용하는 것 이다. CardView.swift 에서 offset 을 추가한다.

  • ZStack을 리턴해야 그 위에 drag gesture 를 추가할 수 있다.
  • body 안에 선언된 drag 는
    • dragging 하면서 기록되는 움직임에 따라 onChagned event 가 발생한다.
      이때 offset 값을 변경하면서 사용자의 drag motion 과 일치하도록 바꾼다.

      예를들어 사용자가 (0, 0)에서 시작했고 사용자가 (200, -100) 으로 드래그 했을 때 onChanged 가 trigger 되어 x축으로 200, y축으로 -100 만큼 이동한다. 결론적으로 컴포넌트는 오른쪽 위로 사용자의 손가락에 맞춰 이동된다.
    • onEnded event 는 사용자가 dragging 을 멈췄을 때 발생한다.(손가락이 스크린에서 떨어졌을 때)
      이 시점에 drag 가 어느 방향으로 이동했냐 (판단은 조건문에 따라) 판단되서 left 나 right 결과가 나온다.
  • 마지막으로 geture modifier 를 적용하면 된다.

Combining gestures for more complex interactions

두개의 제스쳐를 합쳐보자

  • Sequenced : 제스쳐 뒤 제스쳐
  • Simultaneous : 제스쳐 동시에 active
  • Exclusive : 둘다 동시에 추가되었지만 한번에 하나씩만 active

longpress 제스쳐를 drag 에 추가해본다.

    @GestureState var isLongPressed = false
let longPress = LongPressGesture()
            .updating($isLongPressed) { value, state, transition in
                state = value
            }
            .simultaneously(with:drag)
   .gesture(longPress)
        .scaleEffect(isLongPressed ? 1.1 : 1)

Key points

  • 기본 제스쳐 사용
  • 커스텀 제스쳐 사용
  • 두개의 제스쳐 합쳐서 사용

 

swiftUI gesture documentation

 

Apple Developer Documentation

 

developer.apple.com

 

728x90

'iOS > SwiftUI' 카테고리의 다른 글

#12 Conditional Views  (0) 2020.10.23
#11 Lists & Navigation  (0) 2020.10.22
#9 State & Data Flow  (0) 2020.10.22
#8 Introducing Stacks & Containers  (0) 2020.10.22
Inset이 뭘까  (0) 2020.10.21

댓글