Reputation: 891
I have a list in my macOS app’s sidebar. When I add the .onDrag
modifier, dragging NSItemProvider
works correctly, but clicking/selecting the item to trigger the NavigationLink
gets blocked.
struct ContentView: View {
var body: some View {
NavigationView {
List(Data.items) { item in
NavigationLink(
destination: Text(item.text),
label: {
Text(item.text)
.lineLimit(5)
// Enabling dragging with .onDrag {} disables click and selection:
.onDrag { return NSItemProvider(object: item.url as NSURL) }
})
}
Text("Placeholder")
}
}
}
How can I add the drag behavior while keeping the normal list selection behavior intact?
Here ist the rest of the Minimal Reproducible Example:
import SwiftUI
@main
struct ListDragExampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct Data {
struct Item: Identifiable {
let id = UUID()
let text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
let url = URL(string: "http://example.com")!
}
static let items = [
Item(),
Item(),
Item()
]
}
Upvotes: 14
Views: 1054
Reputation: 61
I am having the same issue, and from what I could find, it's actually a bug in SwiftUI. I may be able to contribute some more details to the discussion:
NavigationLink
. I have a plain List
with custom item views and it's presenting the same erratic behavior;View
in them, such as the blank spaces beside Text
views. When I click on those areas (the "background", see the image below), I can still select the item, but the dragging mechanism doesn't work;List
item, it won't accept it.Since I don't have enough reputation yet, please click this link to see the image.
Overall, it seems to me that whenever the item that accepts either drags or drops has subviews—being a simple Text
or a more complex layout, such as the one I showed in the picture—the dragging mechanism disables selection whenever the mouse cursor hits inside one of those subviews, while only allowing drags and drops to occur by starting or ending inside their frames.
On the code below, the selection mechanism will work when clicking on the area to the right of the "Short" item, but the drag will only be triggered if it starts inside the Text
view's frame.
struct ExampleList: View {
private let data = ["Short", "Average", "Loooooooooooong"]
@State private var selected = Set<String>()
var body: some View {
List(data, id: \.self, selection: $selected) { text in
Text(text) // Clicking outside the frame selects it...
// ...but clicking inside starts the drag mechanism.
.onDrag { NSItemProvider(object: text as NSString) }
}
}
}
Hope this helps. Cheers from Brazil!
Upvotes: 6