Drag 제스쳐

SteadySlower·2022년 8월 17일
0

구현하고자 하는 것

예전에 구현한 것인데 포스팅을 깜빡하고 잊었네요. 지금 구현하고자하는 것은 드래그 제스처를 활용해서 단어의 암기 여부를 DB에 기록하는 기능입니다. 그리고 맞은 단어는 초록색, 틀린 단어는 노란색으로 색도 바꾸어 줍니다.

물론 UITableView와 유사한 List를 쓰면 더 쉽게 해당 기능을 더 간단하게 구현할 수도 있습니다만 우리는 좀 더 우리 입맛에 맞게 커스터마이징하기 위해서 드래그를 직접 구현합니다.

구현

position 선언하기

position을 통해서 View를 좌우로 움직여 줄 예정입니다. position에는 View의 center를 정의해줄 수 있습니다. 우리는 Cell을 좌우로만 움직여 줄 생각이므로 y 값은 그대로 local의 center로 두고 x는 기존의 center 값에 dragWidth를 더해줍니다. 이 dragWidth 값은 DragGesture를 통해 바꿀 예정입니다. @State로 선언된 변수이므로 변경이 된다면 View의 위치가 바뀔 것입니다.

// View의 @State 속성
@State private var dragWidth: CGFloat = 0

// View에 position 선언
.position(x: proxy.frame(in: .local).midX + dragWidth, y: proxy.frame(in: .local).midY)

DragGesture 선언하기

먼저 DragGesture를 선언해봅시다.

minimumDistance는 드래그로 인식하는 최소한의 거리를 의미합니다. 30pt 이상 드래그 해야지만 드래그 동작으로 인식합니다.

coordinateSpace는 드래그한 위치를 인식할 때 기준이 되는 공간을 의미합니다. global로 설정하면 전체 화면을 기준으로 좌표를 구하고 local을 설정하면 Drag가 연결된 View 안에서의 좌표값을 인식합니다.

DragGesture(minimumDistance: 30, coordinateSpace: .global)

드래그를 통해 실행할 메소드 연결하기

onChanged는 드래그를 하는 도중에 onEnded는 드래그가 끝나면 실행되는 메소드입니다. 각각에 클로저를 전달하면 됩니다.

클로저는 DragGesture.Value 타입을 인자로 받는데요. 해당 타입은 DragGesture에 대한 많은 정보를 담고 있습니다. 그 중에 우리는 translation이라는 속성을 사용하는데요. 이 속성은 드래그의 시작 위치에서 끝 위치까지를 CGSize로 나타낸 것입니다.

우리는 View를 좌우로만 움직일 예정이므로 CGSize 중에 width만 사용합니다. onChanged에는 해당 값을 미리 선언해놓은 @State 변수인 dragWidth에 할당합니다. 이렇게 하면 @State 변수가 변경되므로 position이 변경되면서 View가 이동하게 됩니다.

onEnded에서는 dragWidth 값을 0으로 바꾸어서 View를 원래 자리로 돌려놓습니다. 그리고 width가 양수이면 (= 오른쪽으로 드래그한 경우) 단어를 성공처리하고, 음수이면 (= 왼쪽으로 드래그한 경우) 단어를 실패처리합니다.

// DragGesture 객체
DragGesture(minimumDistance: 30, coordinateSpace: .global)
  .onChanged({ value in
      self.dragWidth =  value.translation.width
  })
  .onEnded({ value in
      self.dragWidth = 0
      if value.translation.width > 0 {
          viewModel.updateStudyState(to: .success)
      } else {
          viewModel.updateStudyState(to: .fail)
      }
  })

DragGesture 연결하기

마지막으로 해당 DragGesture를 .gesture()를 통해 View에 제스쳐를 연결합시다.

.gesture(DragGesture(minimumDistance: 30, coordinateSpace: .global)
    .onChanged({ value in
        self.dragWidth =  value.translation.width
    })
    .onEnded({ value in
        self.dragWidth = 0
        if value.translation.width > 0 {
            viewModel.updateStudyState(to: .success)
        } else {
            viewModel.updateStudyState(to: .fail)
        }
    })
)

마치며…

좀 더 공부를 해보니 Drag를 통해서 View를 이동하는 방법은 위 처럼 @State를 통해 이동할 수도 있지만 @GestureState 기능을 활용하면 더 직관적이고 쉽게 이동할 수 있더라구요. 다음 포스팅에서 한번 다뤄보도록 하겠습니다.

profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.

0개의 댓글