SwiftUI - Loss of .onDelete Functionality in List as a result of DragGesture

149 views Asked by At

The DragGesture() causes loss of functionality of the .onDelete function inside of the list. I made a basic example of the interaction:


class MenuViewModel: ObservableObject {
  @Published var dragEnabled: Bool = true
}

struct RootView: View {
  @StateObject var viewModel = MenuViewModel()

  var body: some View {
    ZStack {
      NavView()
    }
    .environmentObject(viewModel)
    // Can be diabled on ChildView, but will need to be re-enabled on RootView
    .gesture(DragGesture()
      .onChanged { _ in
        guard viewModel.dragEnabled else { return }
        print("Drag Gesture Active")
      })
  }
}

struct NavView: View {
  var body: some View {
    NavigationView {
      NavigationLink {
        ChildView()
      } label: {
        Text("Go to ChildView")
      }
      Text("Drag Gesture needs to be enabled")
    }
    .navigationViewStyle(.stack)
  }
}

struct ChildView: View {
  @EnvironmentObject var viewModel: MenuViewModel
  @State var list = ["1", "2", "3"]

  var body: some View {
    List {
      ForEach(list, id: \.self) { item in
        Text(item)
      }
      .onDelete { indexSet in
        print("OnDelete Works!")
        list.remove(atOffsets: indexSet)
      }
      .navigationTitle("OnDelete Enabled")
    }
    .onAppear {
      viewModel.dragEnabled = false
      print("Drag Gesture Disabled")
    }
    .onDisappear {
      viewModel.dragEnabled = true
      print("Drag Gesture Enabled")
    }
  }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        RootView()
    }
}

Attempted to use:

  • .simultaneously(with:
  • .highPriorityGesture(
  • .allowsHitTesting(false)
  • changing location of gesture modifier
  • creating custom gesture for swipe
  • disabling gesture if on specific screen (causes rootView to refresh)
  • Using ObservedObjects to pass value between views
  • Using EnvironmentObject to pass value into environment
  • Using Environment value to pass value into environment
  • .onReceive/.onAppear/.onDisappear/.onChange

Nothing is working as expected. Any suggestions would be appreciated! I know in this example the DragGesture does not do anything. I am using the DragGesture in my app so users can drag a side menu into view.

1

There are 1 answers

1
ChrisR On BEST ANSWER

You can use GestureMask to enable/disable parent or child gestures. Do this in RootView:

  var body: some View {
    ZStack {
      NavView()
    }
    .environmentObject(viewModel)
    // Can be diabled on ChildView, but will need to be re-enabled on RootView
    .gesture(DragGesture()
      .onChanged { _ in
        guard viewModel.dragEnabled else { return }
        print("Drag Gesture Active")
      }, including: viewModel.dragEnabled ? .gesture : .subviews) // here
  }
}