I made this SwiftUI-View. Only the button shall trigger the code, but the whole VStack reacts when it becomes tapped. Means: the code within the Button-closure is executed. One can say, that the whole VStack-content is clickable.
How can I restrict the code, contained in the Button-closure, to only the button? Respectively: What's the reason for this weird behavior?
ForEach(filteredTasks, id: \.self) { task in
VStack(alignment: .leading) {
VStack {
Text(task.title)
.bold()
Text(task.desc)
.lineLimit(2)
}.strikethrough(task.status == Status.done.rawValue)
LabeledContent {
Text(dateFormatter.string(from: task.createdAt))
.lineLimit(2)
} label: {
Text("Created at: ")
}
LabeledContent {
Text(dateFormatter.string(from: task.modifiedAt))
.lineLimit(2)
} label: {
Text("Deleted at: ")
}
Button {
if task.hasBeenDeleted == true {
task.hasBeenDeleted = false
} else {
task.status = Status.open.rawValue
}
do {
try context.save()
} catch {
print(error)
}
filteredTasks = tasks
} label: {
Label("Recreate", systemImage: "trash")
.frame(height: 40)
.frame(maxWidth: .infinity)
.background(.blue)
.foregroundStyle(.white)
.fontWeight(.bold)
.clipShape(RoundedRectangle(cornerRadius: 8))
}
}
}
You can add the .buttonStyle(.borderless) modifier to your button; this tells SwiftUI to constrain the button's tap target to just the button's actual frame rather than allowing the List row's gesture to take over.
Alternatively, .buttonStyle(.plain) can work, but .borderless is generally more reliable for this specific issue within Lists.
Ultimately, the fix involves either restructuring the view hierarchy or using .buttonStyle(.borderless) to isolate the button's tap target.