I am trying to implement the ability to move rows in a hierarchical SwiftUI List
via drag+drop. My List
is build with recursive ForEach
loops:
import SwiftUI
struct FileItem: Hashable, Identifiable, CustomStringConvertible {
var id: Self { self }
var name: String
var children: [FileItem]
var description: String {
return children.isEmpty ? " \(name)" : " \(name)"
}
}
struct ContentView: View {
let fileHierarchyData: [FileItem] = [
FileItem(name: "users", children:
[FileItem(name: "user1234", children:
[FileItem(name: "Photos", children:
[FileItem(name: "photo001.jpg", children: []),
FileItem(name: "photo002.jpg", children: [])]),
FileItem(name: "Movies", children:
[FileItem(name: "movie001.mp4", children: [])]),
FileItem(name: "Documents", children: [])
]),
FileItem(name: "newuser", children:
[FileItem(name: "Documents", children: [])
])
]),
FileItem(name: "private", children: [])
]
var body: some View {
List {
ForEach(fileHierarchyData) { item in
RowView(item: item)
}
}
}
}
struct RowView: View {
var item: FileItem
var body: some View {
let children = item.children
DisclosureGroup(content: {
ForEach(0..<children.count, id: \.self) { idx in
let child = children[idx]
if (child.children.isEmpty) {
Text(child.description)
} else {
RowView(item: child)
}
}
.onMove(perform: move)
}, label: {
Text(item.description)
})
}
}
func move(from source: IndexSet, to destination: Int) {
print("FROM: \(source)")
print("TO: \(destination)")
}
One reason I use nested ForEach
loops us so I can make use of the onMove
function to specify how to reorder my data. However, as implemented, I can only call that function within the same hierarchy level of my data, not in between hierarchies. For example, I could reorder user1234 and newuser from the fileHierarchyData array, but I could not bring Photos to the same level as these two. Hence my question: How can I make the reordering work between hierarchy levels? I currently build my app for macOS in Xcode 14.1 + Swift 5.