I have an ObservableObject that has a member property with the @GestureState wrapper. In my View, how do I get access to the GestureState property?
I've already tried using dot notation with the $ binding to try to expose the GestureState but it doesn't like that
My AppState ObservableObject:
class AppState: ObservableObject {
    let objectWillChange = ObservableObjectPublisher()
    @GestureState var currentState: LongPressState = .inactive
    public enum LongPressState: String {
        case inactive = "inactive"
        case pressing = "pressing"
        case holding = "holding"
    }
}
The implementation of the object in my code:
@ObservedObject var appState: AppState
.
.
.
let longPress = LongPressGesture(minimumDuration: minLongPressDuration)
   .sequenced(before: LongPressGesture(minimumDuration: 5))
   .updating(appState.$currentState) { value, state, transaction in
      switch value {
      case .first(true):
         state = .pressing
      case .second(true, false):
         state = .holding
      default:
         state = .inactive
      }
}
I'm actually not getting any buildtime errors in this View but it invalidates the View higher up the hierarchy. If I replace the @ObservedObject with a local @GestureState property then it works fine.
I have found a workaround that works perfectly.
The idea is simple: You have your currentState two times.
GestureState
ObservableObject class as Published
This is necessary since GestureState can only be declared within a view. The only thing left to do now is to somehow sync them.
Here is one possible solution: (using onChange(of:))
class AppState: ObservableObject {
    @Published var currentState: LongPressState = .inactive
    
    enum LongPressState: String { ... }
    ...
}
struct ContentView: View {
    @StateObject private var appState = AppState()
    @GestureState private var currentState: AppState.LongPressState = .inactive
     
    var body: some View {
        SomeView() 
            .gesture(
                 LongPressGesture() 
                     .updating($currentState) { value, state, transaction in
                         ...
                     }
            )
            .onChange(of: currentState) { appState.currentState = $0 } 
    }
}
I have found that the animation was kind of buggy. Adding an onEnded to the gesture fixed it (DragGesture).
.onEnded { 
   appState.currentState = .inactive //if you are using DragGesture: .zero (just set to it's initial state again)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With