Adding contextMenu to a Button within a List prevents default Button functionality
Actually this is a question to Apple... meanwhile here is a possible solution. Tested with Xcode 11.4
List {
button
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.contentShape(Rectangle())
.contextMenu {
button
}.onTapGesture {
self.on.toggle()
}
}
if you want highlight on row tap then it needs to apply custom ButtonStyle. For example you can consider solution in Custom Button in SwiftUI List
SwiftUI List selection doesn’t show If I add a NavigationLink and a .contextMenu to the list. Is this a known bug?
We can disable context menu button(s) for the moment of construction in edit mode (because the button is a reason of issue).
Here is a possible approach - some redesign is required to handle editMode
inside context menu (see also comments inline).
Tested with Xcode 13.2 / iOS 15.2
struct ContentViewSelection: View {
@State private var selection: String?
let names = ["Cyril", "Lana", "Mallory", "Sterling"]
var body: some View {
NavigationView {
List(names, id: \.self, selection: $selection) { name in
// separated view is needed to use editMode
// environment value
NameCell(name: name)
}
.toolbar {
EditButton()
}
}
}
}
struct NameCell: View {
@Environment(\.editMode) var editMode // << !!
let name: String
var body: some View {
NavigationLink(destination: Text("Hello, world!")) {
Text(name)
}
.contextMenu {
if editMode?.wrappedValue == .inactive { // << !!
Button(action: {}) {
Text("Tap me!")
}
}
}
}
}
SwiftUI, Core Data - Delete List Item with Context Menu
Instead of trying to derive an IndexSet
from ForEach
, which doesn't immediately expose one for you, you could create a separate delete method:
.contextMenu { Button(role: .destructive, action: {
deleteExercise(exercise)
}) {
Label("Delete Exercise", systemImage: "trash")
} }
func deleteExercise(_ exercise: Exercise) { //I'm making an assumption that your model is called Exercise
withAnimation {
viewContext.delete(exercise)
viewContext.save()
}
}
In regards to your last question:
I am also wondering why I don't need to specify the IndexSet when using .onDelete
You don't need to specify it because it's sent as a parameter by onDelete
-- that's what your deleteExercise(offsets:)
is receiving from the onDelete
modifier.
SwiftUI: Conditional Context Menu Shown Unexpectedly
Works fine with Xcode 14 / iOS 16
Here is possible workaround for older versions (it is possible to try different places for .id
modifier to have appropriate, acceptable, UI feedback)
Tested with Xcode 13.4 / iOS 15.5
Text("Long press me. Editing: \((editMode?.wrappedValue == .active).description)")
.contextMenu(editMode?.wrappedValue == .active ? nil : contextMenu)
.id(editMode?.wrappedValue) // << this !!
Related Topics
Avplayer Can't Resume After Paused + Some Waiting
Why It Is Called the Memberwise Initialiser
Swift Alternative to Respondstoselector:
Contextmenu on a Rounded Lineargradient Produces Sharp Edges in Swiftui
Why Does Using Dynamictype on a Force Unwrapped Nil Optional Value Type Work
How to Subclass a Class Which Doesn't Have Any Designated Initializers
How to Set Realtime Thread in Swift
New Fuitableviewdatasource - How to Use? Swift 3
Using Vapor-Fluent to Upsert Models
How to Test an Optionset with a Switch Statement
Implementing Reconnection with Urlsession Publisher and Combine
Get Color of Point in a Skscene Swift
Use Different Googleservice-Info.Plist for Single Project in Xcode Using Swift4
Is Dispatchsemaphore a Good Replacement for Nslock
Having Trouble with Nstimer (Swift)