I have the following view that works perfectly fine on macOS:
public struct DropView: View {
@Bindable var store: StoreOf<Feature>
@State var isDropTargeted = false
public init(
store: StoreOf<Feature>
) {
self.store = store
}
public var body: some View {
Group {
if isDropTargeted && store.dropsAccepted {
ZStack {
Color.accentColor.opacity(0.2)
VStack {
Image(systemName: "arrow.up.document")
.symbolRenderingMode(.hierarchical)
.resizable()
.scaledToFit()
.frame(width: 64, height: 64)
Text("Add file")
.foregroundStyle(.secondary)
}
}
} else {
Color.clear
}
}
.dropDestination(for: URL.self) { urls, _ in
store.send(.filesDropped(urls))
return store.dropsAccepted
} isTargeted: { targeted in
isDropTargeted = targeted
}
}
}
It does not work on iOS or iPadOS though, neither in the simulator nor on a real device. (I made sure that dropsAccepted
is true.)
I've tried different things, none of which succeeded:
onDrop
instead.contentShape(Rectangle())
prevents me from interacting with the underlying view but doesn't change anything regarding the dropping..dropDestination
to the color (blue or clear, with or without contentShape
) doesn't help either.When the color is blue instead of clear the dragged file representation gets a "forbidden" icon when it is dragged over the view. Nothing else changes. Dropping isn't possible and isDropTargeted
isn't set to true
either.
Does anyone have an idea about what could be going on here?
Edit: Not sure if this is related but I just added .draggable(url)
to another view in the same app. On the Mac I can drag an image out. On iOS nothing happens.
Seems like Sweeper was on the right track.
The Files app on iOS seems not to to provide URL
s.
In order to get them I needed to create a Transferable
item with a FileRepresentation
:
struct TransferItem: Transferable, Equatable, Sendable {
public var url: URL
static var transferRepresentation: some TransferRepresentation {
FileRepresentation(contentType: .item) { item in
SentTransferredFile(item.url)
} importing: { received in
@Dependency(\.fileClient) var fileClient
let temporaryFolder = fileClient.temporaryReplacementDirectory(received.file)
let temporaryURL = temporaryFolder.appendingPathComponent(received.file.lastPathComponent)
let url = try fileClient.copyItemToUniqueURL(at: received.file, to: temporaryURL)
return Self(url)
}
}
}
And then use it like this:
.dropDestination(for: TransferItem.self) { items, _ in
let urls = items.map(\.url)
store.send(.filesDropped(urls))
return store.dropsAccepted
} isTargeted: { targeted in
isDropTargeted = targeted
}