SwiftUI Gestures
Want more? Subscribers can view all 470 episodes. New episodes are released regularly.
Adding Drag Gesture
We will start by defining the state for our drag gesture. We will define the active and inactive state along with the translation amount while dragging.
enum DragInfo {
case inactive
case active(translation: CGSize)
var translation: CGSize {
switch self {
case .inactive:
return .zero
case .active(let t):
return t
}
}
var isActive: Bool {
switch self {
case .inactive: return false
case .active: return true
}
}
}
Defining Gesture State
Next we will define the gesture state parameter for the drag gesture. We will also create a gesture to update the property and attach this gesture to the last card view along with the offset set using the translation amount. Next we will inspect the drag gesture and choose a value for .offset
and .scaleEffect
. Since we now have more than one statement, we have to explicitly add the return
keyword with our ZStack
.
@GestureState var dragInfo = DragInfo.inactive
var body: some View {
let gesture = DragGesture()
.updating($dragInfo) { (value, dragInfo, _) in
dragInfo = .active(translation: value.translation)
}
return ZStack {
CardView(title: "Walmart", color: .blue)
.offset(x: 0, y: dragInfo.isActive ? -400 : -40)
.scaleEffect(dragInfo.isActive ? 1 : 0.90)
CardView(title: "Target", color: .red)
.offset(x: 0, y: dragInfo.isActive ? -200 : -20)
.scaleEffect(dragInfo.isActive ? 1 : 0.95)
CardView(title: "? Card", color: .black)
.offset(dragInfo.translation)
.gesture(gesture)
}
.offset(x: 0, y: 80)
.animation(.spring(mass: 1.0, stiffness: 100, damping: 20, initialVelocity: 0))
}
Adding Rotation Effect
Currently, the cards are slightly up due to the .offset
, we will rotate these cards by setting the angle and axis for the 3D effect. Note that we are inspecting the gesture while choosing the value for angle dynamically.
To coordinate the rotation and translation movement for the top card, we will rotate the card on the 2D plane and set the angle using the width of the translation obtained from the gesture.
To make the top card move up and down we will set the .rotation3DEffect
using the height of translation along the x-axis.
@GestureState var dragInfo = DragInfo.inactive
var body: some View {
let gesture = DragGesture()
.updating($dragInfo) { (value, dragInfo, _) in
dragInfo = .active(translation: value.translation)
}
return ZStack {
CardView(title: "Walmart", color: .blue)
.offset(x: 0, y: dragInfo.isActive ? -400 : -40)
.rotation3DEffect(Angle(degrees: dragInfo.isActive ? 20 : 4), axis: (x: 0, y: 0.25, z: 1))
.scaleEffect(dragInfo.isActive ? 1 : 0.90)
CardView(title: "Target", color: .red)
.offset(x: 0, y: dragInfo.isActive ? -200 : -20)
.rotation3DEffect(Angle(degrees: dragInfo.isActive ? 10 : 2), axis: (x: 0, y: 0.25, z: 1))
.scaleEffect(dragInfo.isActive ? 1 : 0.95)
CardView(title: "? Card", color: .black)
.offset(dragInfo.translation)
.rotationEffect(Angle(degrees: Double(dragInfo.translation.width / 10)))
.rotation3DEffect(Angle(degrees: Double(dragInfo.translation.height / 50)), axis: (x: 1, y: 0, z: 0))
.gesture(gesture)
}
.offset(x: 0, y: 80)
.animation(.spring(mass: 1.0, stiffness: 100, damping: 20, initialVelocity: 0))
}