Combine Gestures in a Sequence

An example of using SequenceGesture to create a Long Press + Drag gesture.

SwiftUI provided a few ways to combine gestures. We can use SequenceGesture to combine the concepts from the Long Press and Drag Gestures.

There are a number of ways to create gestures, but for this example I’ll stick with the custom modifier pattern that we used in the previous examples.

  • Create a ViewModifier to encapsulate our state and gestures
  • Create the long press and drag gestures
  • Combine them together with by calling .sequenced() after the first gesture.

When the user completes the long press, the entity will be raised off the surface of the table and the drag gesture will begin. They can drag the entity around the scene. When they release the drag, the entity pops back to the table.

struct Example013: View {
    var body: some View {
        RealityView { ... }
        .modifier(LongPressDragGesture())
    }
}

struct LongPressDragGesture: ViewModifier {

    @State var isDragging: Bool = false
    @State var initialPosition: SIMD3<Float> = .zero

    func body(content: Content) -> some View {
        content
            .gesture(longPress.sequenced(before: dragGesture))
    }

    var longPress: some Gesture {
        LongPressGesture(minimumDuration: 1.0)
            .targetedToAnyEntity()
            .onEnded { value in
                raiseEntity(value.entity) // raise the entity when the long press ends (and the drag starts)
            }
    }

    var dragGesture: some Gesture {
        DragGesture()
            .targetedToAnyEntity()
            .onChanged { value in
                if !isDragging {
                    isDragging = true
                    initialPosition = value.entity.position
                }

                let movement = value.convert(value.gestureValue.translation3D, from: .local, to: .scene)
                value.entity.position = initialPosition + movement

            }
            .onEnded { value in
                isDragging = false
                initialPosition = .zero
                lowerEntity(value.entity) // lower the entity when the drag has ended
            }

    }

    func raiseEntity(_ entity: Entity) {...}
    func lowerEntity(_ entity: Entity) {...}
}

Video demo

Support our work so we can continue to bring you new examples and articles.

Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.

Questions or feedback?