0

I am having an issue with multiple gestures affecting a single list. I want to have a modifier on the list itself that will create a new row if a user taps anywhere outside of a row. However, it triggers in place of the swipe-to-delete button if attempting to tap, as well as simultaneously with taps for the icon and textfield

Here is a contrived example of the issue:

import SwiftUI

struct ToDoItem: Identifiable {
  let id: String = UUID().uuidString
  var isComplete: Bool = false
  var text: String = ""
}

class ToDoViewModel: ObservableObject {
  @Published var items: [ToDoItem] = [ToDoItem(), ToDoItem(), ToDoItem(), ToDoItem(), ToDoItem()]

  func addItem() {
    items.append(ToDoItem())
  }

  func toggleComplete(for item: ToDoItem) {
    if let index = items.firstIndex(where: { $0.id == item.id }) {
      items[index].isComplete.toggle()
    }
  }

  func updateText(for item: ToDoItem, newText: String) {
    if let index = items.firstIndex(where: { $0.id == item.id }) {
      items[index].text = newText
    }
  }

  func deleteItem(withID id: String) {
    items.removeAll(where: { $0.id == id })
  }
}

struct ContentView: View {
  @StateObject var viewModel = ToDoViewModel()

  var body: some View {
    List(viewModel.items) { item in
      HStack {
        Image(systemName: item.isComplete ? "circle.fill" : "circle")
          .onTapGesture {
            print("Tap icon - trigger when tapping circle")
            viewModel.toggleComplete(for: item)
          }
        TextField("Enter text here...", text: Binding(
          get: { item.text },
          set: { viewModel.updateText(for: item, newText: $0) }
        ))
        .onTapGesture {
          print("Tap textfield - trigger when tapping textfield")
        }
      }
      .swipeActions {
        Button("Delete", role: .destructive) {
          print("Tap delete item - trigger when tapping delete swipe action button")
          viewModel.deleteItem(withID: item.id)
        }
      }
    }
    .onTapGesture {
      viewModel.addItem()
      print("Tap list - ONLY trigger when not tapping in a row")
    }
  }
}

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

Expected: The tap gesture modifier on the list should only create a new row when tapping outside of a row. My understanding is that child gesture components would be prioritized, but that it not the case in this example. The view has to be a List, and cannot be a ScrollView/VStack combo

I have been able to solve the list modifier tap gesture not interacting with the icon and the textfield, but the issue with the swipe to delete has been very difficult to resolve

Sam
  • 13
  • 4

0 Answers0