Can I disable a SwiftUI View from being a draggable source, but still leave it enabled as a dropDestination?

My app has a collection of Cell Views. some of the views' model objects include a Player, and others do not. I want to use drag and drop to move a player from one cell to another. I only want cells that contain a player to be valid drag sources. All cells will be valid drop destinations. When I uncomment the .disabled line both drag and drop become disabled. Is it possible to keep a view enabled as a dropDestination but disabled as a draggable source?

        VStack {
            Image("playerJersey_red")
            if let player = content.player {
                Text(player.name)
            }
        }
        .draggable(content)
//        .disabled(content.player == nil)
        .dropDestination(for: CellContent.self) { items, location in

One thing I tried was to wrap everything in a ZStack and put a rectangle with .opacity(0.02) above the Image/Text VStack. I then left draggable modifying my VStack and moved dropDestination to the clear rectangle. This didn't work as I wasn't able to initiate a drag when tapping on the rectangle. Any other ideas or suggestions? thanks

Thank you for your question. I recommend providing a focused sample project, such as the image Image(“playerJersey_red”), which we will all be missing. I will need to replace it with a different image. Regarding the dropDestination cellContent, I understand that you define it, but it would be beneficial to have a sample that can be executed quickly and shared with others for verification.

I think it is possible to have a view enabled as a drop destination but disabled as a draggable source based on certain conditions. The issue you're encountering with the .disabled modifier affecting both dragging and dropping could be because it disables all user interactions for the view. Instead, you should conditionally apply the .draggable modifier only when there is a player available?

Use content.player.map { $0 } to provide a value only when player is not nil. This makes the view draggable only if a player exists and should keep the .dropDestination modifier without any conditions since you want all cells to be valid drop targets? I need to play with it and see I think as I haven’t even done that for so long, let you get the focused sample posted so I can start working on those 2 modifications to see if I’m correct this time. Invite swiftUI experts here to provide their opinion, of course as probably there are better ways to do that.

Albert Pascual
  Worldwide Developer Relations.

Hi Albert, Thank you for your interest in my question :-) here is a barebones sample project to demonstrate my challenge.

There are two player cells, and I want to be able to move the player (Messi) from the cell on the left to the cell on the right using a drag gesture. However I do not want the cell on the right to be a drag source (because it is empty). The only way I can find to prevent the right side cell from being a drag source also prevents it from being a drop destination. Is there a way I can configure PlayerView to:

  1. be a drag source when it contains a player
  2. always be a drop destination.

thanks again for your interest and assistance with this.

struct ContentView: View {
    var body: some View {
        HStack {
            PlayerView(content: .init(player: .mock))
            PlayerView(content: .init())
        }
        .padding()
    }
}

struct PlayerView: View {
    var content: CellContent
    var body: some View {
        VStack {
            Image("jersey")
            if let player = content.player {
                Text(player.last)
            }
        }
        .draggable("player")
//        .disabled(content.player == nil)
        .dropDestination(for: String.self) { items, location in
            if let firstItem = items.first {
                print("\(firstItem)")
            }
            return true
        }
    }
}

class CellContent: Identifiable, Codable {
    let id: UUID
    var player: Player?
    
    init(player: Player? = nil) {
        self.id = UUID()
        self.player = player
    }
}
class Player: Codable, Identifiable {
    static let mock = Player(first: "Leo", last: "Messi", number: "10")
    var first: String
    var last: String
    var number: String
    let id: UUID
    
    init(first: String, last: String, number: String, absent: Bool = false) {
        self.first = first
        self.last = last
        self.number = number
        self.id = UUID()
    }
}

Can I disable a SwiftUI View from being a draggable source, but still leave it enabled as a dropDestination?
 
 
Q