How to Prevent Retrigger on SwiftUI On Touch Down Implementation

47 views Asked by At

I followed this medium article in order to implement an on touch down/on touch up gesture control for my app. It works but it can be retriggered on the same element/view. The application is an instrument and this results in the keys occasionally getting stuck in the triggered position if another touch is detected. So occasionally some notes will just get stuck in the on position and stay there. The code is as follows:

 .gesture(
         DragGesture(minimumDistance: 0)
             .onChanged { _ in
                 if !triggered{
                      triggered = true
                      model.noteOn(note: midiVal)            
                 }
             }
             .onEnded { _ in
                 model.noteOff(note: midiVal)
                 triggered = false
             }
)

How can I adjust this implementation so that refiring of a note that's already pressed can't happen?

1

There are 1 answers

0
Brent Brinkley On

So I found a solution to this. What you want to do is use @GestureState and .updating() on DragGesture

// within your View Struct

@GestureState private var triggered = false

SomeView()
  .simultaneousGesture(
                    DragGesture(minimumDistance: 0)
                        .updating($triggered, body: { (value, state, transaction) in
                            state = true
                        })
                )
                .triggerNote {
                    triggered ? model.noteOn(note: midiVal) : model.noteOff(note: midiVal)
                }

@GestureState automatically goes back to its original state when the touch is released. From there just create a callback View extension that lets you check the state of the touch. My implementation looks like this:

extension View {
    func triggerNote(playNote: (() -> Void)) -> some View {
        playNote()
        return self
    }
}