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.