Sequencing Gestures in SwiftUI
Written by Team Kodeco
Sequencing gestures in SwiftUI allows you to create a series of interactions that respond to user input in a particular order. This provides a more intuitive user experience and allows for more complex and interactive behaviors in your views.
In this chapter, you’ll explore how to sequence a long press gesture followed by a rotation gesture. Think of it as an unlocking mechanism — the user has to unlock the rotation by long pressing on the image. Once the image is unlocked, it can then be rotated.
Let’s dive into the implementation:
// Define the states for rotation
enum RotationState: Equatable {
case inactive
case pressing
case rotating(angle: Angle)
var angle: Angle {
switch self {
case .inactive, .pressing:
return .zero
case .rotating(let angle):
return angle
}
}
var isRotating: Bool {
switch self {
case .inactive, .pressing:
return false
case .rotating:
return true
}
}
}
struct ContentView: View {
@GestureState private var rotationState = RotationState.inactive
@State private var rotationAngle = Angle.zero
var body: some View {
let longPressBeforeRotation = LongPressGesture(minimumDuration: 0.5)
.sequenced(before: RotationGesture())
.updating($rotationState) { value, state, _ in
switch value {
// Long press begins
case .first(true):
state = .pressing
// Long press confirmed, rotation may begin
case .second(true, let rotation):
state = .rotating(angle: rotation ?? .zero)
// Rotation ended or the long press cancelled
default:
state = .inactive
}
}
.onEnded { value in
guard case .second(true, let rotation?) = value else { return }
self.rotationAngle = rotation
}
Image(systemName: "arrow.triangle.2.circlepath")
.font(.system(size: 100))
.rotationEffect(rotationState.angle + rotationAngle)
.foregroundColor(rotationState.isRotating ? .blue : .red)
.animation(.default, value: rotationState)
.gesture(longPressBeforeRotation)
}
}
Your preview should look like this:
In this example, users need to perform a long press on the arrow image before they can rotate it. The image will turn blue when it’s rotating and revert to red when it’s not. The rotation angle is kept after the gesture ends, allowing users to rotate the image multiple times.
Here’s a detailed breakdown of the code:
-
RotationState enum: This custom enumeration represents the states our gesture can be in:
.inactive
,.pressing
or.rotating
. It holds anAngle
for the.rotating
state. -
GestureState and State variables: Two state properties,
rotationState
androtationAngle
, are declared. TherotationState
is marked with@GestureState
, which resets to its initial value after the gesture ends. TherotationAngle
is marked with@State
to keep its value after the gesture ends. -
LongPressGesture and RotationGesture: The
LongPressGesture
andRotationGesture
are created and sequenced together. TheLongPressGesture
must be recognized before theRotationGesture
can begin. This is achieved by using the.sequenced(before:)
method. -
Gesture modifiers: The
updating
andonEnded
modifiers are used to updaterotationState
androtationAngle
based on the current value of the gesture. -
Image view: The image view uses the
rotationEffect
modifier to apply the rotation, theforegroundColor
modifier to change the color based on the rotation state and thegesture
modifier to apply the combined gesture. -
Animation: An animation is applied to the image view to make the rotation and color change smoothly. The
value:
parameter is used to tell SwiftUI to animate whenever therotationState
changes.
The power of this approach is in its flexibility. By sequencing gestures and managing the state properly, you can create complex interactions that provide a fluid and intuitive user experience.
This example showcases how you can sequence gestures to create complex and interactive UIs in SwiftUI. Sequencing gestures not only provides a more intuitive way to interact with your app, but also allows you to create unique and engaging experiences.