0

I wrote a short program to test Transferable with a List of objects for an easy implementation of drag and drop. My list already provided movable items (taking for granted from the SwiftUI List). After I added Transferable that functionality was broken. Does anyone know what I am doing wrong? In the example code uncommenting draggable disables the movable functionality while enabling drag and drop.

struct EditableListApp: App {
    @State private var model: [Profile] = Profile.profiles()
    
    var body: some Scene {
        WindowGroup {
            ContentView(profiles: $model)
        }
    }
}

struct ContentView: View {
    @Binding var profiles: [Profile]
    
    var body: some View {
        HStack(alignment: .top, spacing: 0) {
            ProfileList(profiles: $profiles)
            DetailView()
        }
    }
}

struct ProfileList: View {
    @Binding var profiles: [Profile]
    
    var body: some View {
        List($profiles, editActions: [.move, .delete]) { $item in
            ProfileView(profile: $item)
        }
    }
}

struct ProfileView: View {
    @Binding var profile: Profile
    
    var body: some View {
        HStack {
            Text(profile.name)
                .font(.title)
                .padding(5)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(5)
        .border(.gray)
        .padding(2)
        
        .contentShape(Rectangle()) // used so everything in the view is draggable
        //.draggable(profile) // uncomment for drag and drop
    }
}

struct DropView: View {
    @Binding var profile: Profile?
    @State private var borderColor = Color.clear
    @State private var borderWidth: CGFloat = 1.0
    
    var body: some View {
        VStack {
            if let binding = Binding<Profile>($profile) {
                ProfileView(profile: binding)
            } else {
                Text("Drop a profile here")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
        }
        .border(borderColor, width: borderWidth)
        
        .dropDestination(for: Profile.self) { items, location in
            profile = items.first

            return true // item is allowed to be dropped
        } isTargeted: { inDropArea in
            borderColor = inDropArea ? .accentColor : .clear
            borderWidth = inDropArea ? 5.0 : 1.0
        }
    }
}

struct DetailView: View {
    @State private var profile: Profile?
    
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            DropView(profile: $profile)
                .frame(minWidth: 300, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
                .border(.gray)
        }
        .padding()
    }
}

struct Profile: Identifiable, Codable {
    var id: UUID = UUID()
    var name: String
    
    static func profiles() -> [Profile] {
        return [Profile(name: "Adam"), Profile(name: "Beat"), Profile(name: "Casper")]
    }
}

extension Profile: Transferable {
    static var transferRepresentation: some TransferRepresentation {
        CodableRepresentation(for: Profile.self, contentType: .profile)
    }
}

extension UTType {
    static var profile = UTType(exportedAs: "de.enovatia.tutorial.profile")
}

Both are built-in features, that should probably not be XOR-ed. So I expect that I miss something important to get it going.

enovatia
  • 230
  • 1
  • 12

0 Answers0