SwiftUI의 .gesture viewModifier에 대한 정리
.gesture viewModifier
SwiftUI에서는 제스쳐를 적용하고 싶은 View에 .gesture를 적용
struct GestureTest: View {
var body: some View {
VStack {
Text("GestureTest")
}
.gesture(
// 여기에 GestureMask를 작성
)
}
.gesture에 GestureMask를 정의해서 적용.
GestureMask에는 DrageGesture, TapGesture, LongPressGesture가 있음.
DragGesture
드래그 제스쳐 적용 예시.
DragGesture의 height값은 아래방향이 (+), 윗방향이 (-) 가 됨.
struct GestureTest: View {
@State var size: CGSize = .zero
@State var condition: String = "Normal"
var body: some View {
VStack {
Text("Drag \(size)")
Text("\(condition)")
}
.gesture(
DragGesture() // 드래그 제스쳐
.onChanged { // 드래그 중
// NOTE: DragGesture의 height값은 아래방향이 +, 윗방향이 -
condition = "Drag onChanged: \($0.translation.height > 0 ? "아래로" : "위로")"
setSize($0.translation)
}
.onEnded { // 드래그 끝
condition = "Drag onEnded"
setSize($0.translation)
}
)
}
func setSize(_ size: CGSize) {
print(size)
let width = CGFloat(Int(size.width))
let height = CGFloat(Int(size.height))
self.size = CGSize(width: width, height: height)
}
}
TapGesture
TapGesture 적용 예시.
제스쳐는 .gesture viewModifier를 중첩해서 적용할 수 있음.
struct GestureTest: View {
@State var size: CGSize = .zero
@State var condition: String = "Normal"
@State var tapCount: Int = 0
var body: some View {
VStack {
Text("Drag \(size)")
Text("\(condition)")
}
.gesture(
DragGesture()
.onChanged {
condition = "Drag onChanged: \($0.translation.height > 0 ? "아래로" : "위로")"
setSize($0.translation)
}
.onEnded {
condition = "Drag onEnded"
setSize($0.translation)
}
)
.gesture( // 제스쳐를 중첩시켜 적용
TapGesture() // 탭 제스쳐
.onEnded { // TapGeture는 onEnded 이벤트만 들어옴
tapCount += 1
condition = "\(tapCount) Tap!!"
}
)
}
func setSize(_ size: CGSize) {
print(size)
let width = CGFloat(Int(size.width))
let height = CGFloat(Int(size.height))
self.size = CGSize(width: width, height: height)
}
}
LongPressGesture
롱프레스 제스쳐 적용 예시.
LongPressGeture는
minimumDuration(최소로 눌러야하는 시간. 초)과
maximumDistance(제스쳐를 성공으로 판단할 최대 거리)를 설정할 수 있음. 누른채로 해당 거리를 벗어나면 취소로 판단.
struct GestureTest: View {
@State var size: CGSize = .zero
@State var condition: String = "Normal"
@State var tapCount: Int = 0
var body: some View {
VStack {
Text("Drag \(size)")
Text("\(condition)")
}
.gesture(
LongPressGesture(minimumDuration: 1) // 롱프레스 제스쳐
.onEnded { _ in condition = "Long Press end" }
)
}
}
위 LongPressGesture의 특징은
'롱프레스하고 손가락을 뗐을 때의 onEnded 이벤트만 들어오기 때문에 누르고 있는 동안 이를 알 수 있는 방법이 없음'
그래서(?) 이를 알 수 있도록 만든 onLongPressGesture viewModifier가 있음.
.onLongPressGesture
onLongPressGesture는 위 LongPressGesture와 동일하게 minimumDuration과 maximumDistance를 제공하고,
onEnded이벤트를 perform 클로저를 통해 전달해 줌.
그리고 onPressingChanged 클로저를 통해 누르고 있는지, 떼고 있는지를 Bool로 전달해 줌.
(왜 LongPressGesture와 onLongPressGesture를 모두 제공하는지는 의문)
struct GestureTest: View {
@State var size: CGSize = .zero
@State var condition: String = "Normal"
@State var tapCount: Int = 0
var body: some View {
VStack {
Text("Drag \(size)")
Text("\(condition)")
}
.onLongPressGesture(minimumDuration: 2, perform: {
condition = "onPressingChanged perform"
}, onPressingChanged: { isPressed in
condition = "onPressingChanged \(isPressed)"
})
}
func setSize(_ size: CGSize) {
print(size)
let width = CGFloat(Int(size.width))
let height = CGFloat(Int(size.height))
self.size = CGSize(width: width, height: height)
}
}