[英]SwiftUI: How to get drag and drop reordering of items to work?
I have the following SwiftUI view:我有以下 SwiftUI 视图:
struct ContentView: View {
@State var model: Model
var body: some View {
ScrollView {
LazyVGrid(columns: columns, spacing: 10) {
ForEach(model.events, id: \.self) { event in
CardView(event: event)
}
.onMove { indices, newOffset in
model.events.move(fromOffsets: indices, toOffset: newOffset)
}
}
}
}
}
However, it doesn't appear that the onMove
closure is executing.但是,似乎没有执行
onMove
闭包。 I believe this is because all gestures are only given to the ScrollView
and so the inner views don't receive the gestures.我相信这是因为所有手势都只提供给
ScrollView
,因此内部视图不会收到手势。
I tried converting this view to a List
, however I don't want the row separators, which in iOS 14 I believe are impossible to hide.我尝试将此视图转换为
List
,但是我不想要行分隔符,我认为它在 iOS 14 中是不可能隐藏的。
So, I was wondering what I need to change to get this to allow the user to drag and drop CardView
s to reorder them.所以,我想知道我需要更改什么才能使它允许用户拖放
CardView
以重新排序它们。 Thanks!谢谢!
According to Apple reply in Drag and Drop to reorder Items using the new LazyGrids?根据 Apple 在Drag and Drop 中的回复以使用新的 LazyGrids 重新排序项目?
That's not built-today, though you can use the View.onDrag(_:) and View.onDrop(...) to add support for drag and drop manually.
这不是今天内置的,尽管您可以使用 View.onDrag(_:) 和 View.onDrop(...) 手动添加对拖放的支持。
Do file a feedback request if you'd like to see built-in reordering support.
如果您想查看内置的重新排序支持,请提交反馈请求。 Thanks!
谢谢!
So the solution using.onDrag &.onDrop provided in my answer for actually duplicated question in https://stackoverflow.com/a/63438481/12299030因此,在我对https://stackoverflow.com/a/63438481/12299030中实际重复问题的回答中提供了 using.onDrag &.onDrop 的解决方案
Main idea is to track drug & drop by grid card views and reorder model in drop delegate, so LazyVGrid animates subviews:主要思想是通过网格卡片视图跟踪药物和掉落,并在 drop delegate 中重新排序 model,因此 LazyVGrid 动画子视图:
LazyVGrid(columns: model.columns, spacing: 32) {
ForEach(model.data) { d in
GridItemView(d: d)
.overlay(dragging?.id == d.id ? Color.white.opacity(0.8) : Color.clear)
.onDrag {
self.dragging = d
return NSItemProvider(object: String(d.id) as NSString)
}
.onDrop(of: [UTType.text], delegate: DragRelocateDelegate(item: d, listData: $model.data, current: $dragging))
}
}.animation(.default, value: model.data)
... ...
func dropEntered(info: DropInfo) {
if item != current {
let from = listData.firstIndex(of: current!)!
let to = listData.firstIndex(of: item)!
if listData[to].id != current!.id {
listData.move(fromOffsets: IndexSet(integer: from),
toOffset: to > from ? to + 1 : to)
}
}
}
As of iOS 15 , .listRowSeparator(.hidden) is available.从iOS 15开始,.listRowSeparator(.hidden) 可用。
To keep the user's order changes, an object-based property wrapper was used.为了保持用户的订单更改,使用了基于对象的属性包装器。 In this example @StateObject was used instead of @State.
在此示例中,使用了@StateObject 而不是@State。
struct ContentView: View {
@StateObject var model: Model = Model()
var body: some View {
List {
ForEach(model.events, id: \.self) { event in
CardView(event: event)
.listRowSeparator(.hidden)
}
.onMove { indices, newOffset in
model.events.move(fromOffsets: indices, toOffset: newOffset)
}
}
}
}
The result looks like this:结果如下所示:
The following variation of the above uses.listStyle(.plain) and an EditButton() for dragging and dropping the rows more easily:上面的以下变体使用 .listStyle(.plain) 和 EditButton() 来更轻松地拖放行:
struct ContentView: View {
@StateObject var model: Model = Model()
var body: some View {
VStack {
EditButton()
List {
ForEach(model.events, id: \.self) { event in
CardView(event: event)
.listRowSeparator(.hidden)
}
.onMove { indices, newOffset in
model.events.move(fromOffsets: indices, toOffset: newOffset)
}
}
.listStyle(.plain)
}
}
}
The result looks like this:结果如下所示:
The following code was used with the above examples for testing:以下代码与上述示例一起用于测试:
class Model : ObservableObject {
@Published var events: [String]
init() { events = (1...10).map { "Event \($0)" }}
}
struct CardView: View {
var event: String
var body: some View {
Text(event)
}
}
You can use a List and hide the separators.您可以使用列表并隐藏分隔符。
.onAppear {
UITableView.appearance().separatorStyle = .none
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.