Skip to content

Instantly share code, notes, and snippets.

@benigumocom
Last active September 12, 2024 10:58
Show Gist options
  • Save benigumocom/98dc0aa829c4f6836b4bfeff61ca11d5 to your computer and use it in GitHub Desktop.
Save benigumocom/98dc0aa829c4f6836b4bfeff61ca11d5 to your computer and use it in GitHub Desktop.
【SwiftUI】Create Draggable Reorder ListView without List 👉 https://android.benigumo.com/20240912/create-draggable-reorder-list-view/
import SwiftUI
struct Fruit: Identifiable, Equatable {
let id = UUID()
let name: String
let color: Color
}
struct DraggableList: View {
@State private var fruits: [Fruit] = [
Fruit(name: "APPLE", color: .red),
Fruit(name: "ORANGE", color: .orange),
Fruit(name: "BANANA", color: .yellow),
Fruit(name: "MELON", color: .green),
Fruit(name: "PEACH", color: .pink),
Fruit(name: "KIWI", color: .brown),
Fruit(name: "GRAPES", color: .purple),
Fruit(name: "LIME", color: .cyan),
Fruit(name: "TOMATO", color: .indigo)
]
@State private var dragging: Fruit?
var body: some View {
ScrollView {
LazyVStack(spacing: 16) {
ForEach(fruits) { fruit in
FruitItemView(fruit: fruit)
.onDrag {
print("onDrag: \(fruit)")
dragging = fruit
//return NSItemProvider() // iOS only
return NSItemProvider(object: NSString(string: "\(fruit.id)"))
} preview: {
//EmptyView() // crash on macOS
PreviewView()
}
.onDrop(
of: [.text], // *
delegate: DropViewDelegate(
fruit: fruit,
fruits: $fruits,
dragging: $dragging
)
)
}
}
}
.padding()
}
}
struct FruitItemView: View {
var fruit: Fruit
var body: some View {
HStack {
Spacer()
Text("\(fruit.name)")
Spacer()
}
.foregroundStyle(.background)
.padding(.vertical, 40)
.background(fruit.color, in: .rect(cornerRadius: 16))
}
}
struct PreviewView: View {
var body: some View {
EmptyView()
}
}
struct DropViewDelegate: DropDelegate {
let fruit: Fruit
@Binding var fruits: [Fruit]
@Binding var dragging: Fruit?
func dropEntered(info: DropInfo) {
print("\(dragging?.name ?? "") on \(fruit.name)")
if dragging != fruit {
let from = fruits.firstIndex(of: dragging!)!
let to = fruits.firstIndex(of: fruit)!
withAnimation {
fruits.move(
fromOffsets: IndexSet(integer: from),
toOffset: to > from ? to + 1 : to
)
}
}
}
func dropUpdated(info: DropInfo) -> DropProposal? {
return DropProposal(operation: .move) // icon on macOS
}
func performDrop(info: DropInfo) -> Bool {
print("performDrop: \(info)")
dragging = nil
return true
}
}
#Preview {
DraggableList()
}
@benigumocom
Copy link
Author

sc 2024-09-12 at 19 20 55

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment