Chapters

Hide chapters

SwiftUI Cookbook

Live Edition · iOS 16.4 · Swift 5.8.1 · Xcode 14.3.1

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:

You can create custom gestures in SwiftUI.
You can create custom gestures in SwiftUI.

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 an Angle for the .rotating state.

  • GestureState and State variables: Two state properties, rotationState and rotationAngle, are declared. The rotationState is marked with @GestureState, which resets to its initial value after the gesture ends. The rotationAngle is marked with @State to keep its value after the gesture ends.

  • LongPressGesture and RotationGesture: The LongPressGesture and RotationGesture are created and sequenced together. The LongPressGesture must be recognized before the RotationGesture can begin. This is achieved by using the .sequenced(before:) method.

  • Gesture modifiers: The updating and onEnded modifiers are used to update rotationState and rotationAngle based on the current value of the gesture.

  • Image view: The image view uses the rotationEffect modifier to apply the rotation, the foregroundColor modifier to change the color based on the rotation state and the gesture 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 the rotationState 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.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.