I have a SwiftUI List that's a sidebar on macOS. For its items I have added the dropDesternation modifier like this:
.dropDestination(for: URL.self) { urls, _ in
for url in urls {
//... adding urls to destination
}
}
return true
} isTargeted: { inDropArea in
if inDropArea {
highlightedItem = item
} else {
highlightedItem = nil
}
}
By default if the cursor is above the item I get no effect, but I want the same effect like using NSOutlineView in AppKit. Here's an example from the Finder:
As you can see I have implemented highlightedItem
in the code above. I can use it to check if an item is targeted and draw a background:
.background {
if item == highlightedItem {
RoundedRectangle(cornerRadius: 5)
.fill(Color.blue)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
But that does not look quite the same:
Interestingly the effect I want is the same you get if you use a selection for the sidebar list like: List(selection: $selectedItem)
There must be a native way to do this so I don't have to fake it and get something that does not look quite right.
shufflingb's workaround is nice but can have performance side effects and I've found a simpler solution.
I've made a view for each list item and used .listRowBackground()
for the background effect, not just .background
:
struct SidebarItemView: View {
@ObservedObject var item: Item
@State private var isTargeted = false
var body: some View {
NavigationLink(value: item) {
Label {
Text(item.title)
} icon: {
Image(systemName: "folder")
}
.onDrop(of: [.image], isTargeted: $isTargeted, perform: { itemProviders in
...
return true
})
}
.listRowBackground(
Color.secondary
.cornerRadius(5)
.opacity(isTargeted ? 1.0 : 0.0)
.padding(.horizontal, 10)
)
}
}