在SwiftUI如何实现拖动移动列表中的任何行?

10 min read

在SwiftUI中,可以通过使用DragGesture和onMove modifiers来实现拖动移动列表中的任何行。

以下是一个基本示例:

struct ContentView: View {
    @State var items = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]

    var body: some View {
        NavigationView {
            List {
                ForEach(items, id: \.self) { item in
                    Text(item)
                        .gesture(
                            DragGesture()
                                .onChanged { gesture in
                                    guard let sourceIndex = self.items.firstIndex(of: item) else {
                                        return
                                    }
                                    let destinationIndex = self.index(for: gesture.translation.height, currentIndex: sourceIndex)
                                    if destinationIndex != sourceIndex {
                                        withAnimation {
                                            self.items.swapAt(sourceIndex, destinationIndex)
                                        }
                                    }
                                }
                        )
                }
                .onMove { indices, newOffset in
                    self.items.move(fromOffsets: indices, toOffset: newOffset)
                }
            }
            .navigationBarTitle("Drag to Move")
            .navigationBarItems(trailing: EditButton())
        }
    }

    func index(for offset: CGFloat, currentIndex: Int) -> Int {
        let newIndex = Int(round(offset / 44.0)) + currentIndex
        return max(0, min(items.count - 1, newIndex))
    }
}

在这里,我们设置一个包含可重新排序项目(字符串)的items数组,并将其传递给ForEach视图。每个项目都附加了一个DragGesture,并在拖动时将其相应地调整。我们使用onMove modifier告诉列表视图每当重新排序时如何调整列表项的顺序。最后,我们为EditButton提供右侧navigationBarItems。