我想知道是否可以使用View.onDrag
和View.onDrop
在一个LazyGrid
中手动添加拖放重新排序?
虽然我能够使用onDrag
使每个Item都可拖动,但我不知道如何实现拖放部分。
下面是我正在试验的代码:
import SwiftUI
//MARK: - Data
struct Data: Identifiable {
let id: Int
}
//MARK: - Model
class Model: ObservableObject {
@Published var data: [Data]
let columns = [
GridItem(.fixed(160)),
GridItem(.fixed(160))
]
init() {
data = Array<Data>(repeating: Data(id: 0), count: 100)
for i in 0..<data.count {
data[i] = Data(id: i)
}
}
}
//MARK: - Grid
struct ContentView: View {
@StateObject private var model = Model()
var body: some View {
ScrollView {
LazyVGrid(columns: model.columns, spacing: 32) {
ForEach(model.data) { d in
ItemView(d: d)
.id(d.id)
.frame(width: 160, height: 240)
.background(Color.green)
.onDrag { return NSItemProvider(object: String(d.id) as NSString) }
}
}
}
}
}
//MARK: - GridItem
struct ItemView: View {
var d: Data
var body: some View {
VStack {
Text(String(d.id))
.font(.headline)
.foregroundColor(.white)
}
}
}
谢谢你,谢谢你
6条答案
按热度按时间nbysray51#
快速用户界面2.0
这是一个简单的演示(没有太多的调整,因为代码增长很快)。
要点是:a)重新排序不假定等待丢弃,因此应当在运行中跟踪; B)为了避免与坐标的跳变,更简单的是处理按网格项目视图放置; c)找到要移动的内容并在数据模型中执行此操作,因此SwiftUI会自动显示视图。
使用Xcode 12 b3/ iOS 14进行测试
编辑
以下是如何修复将拖动项拖到任何网格项之外时永不消失的问题:
第一次
5tmbdcev2#
以下是我的解决方案(基于Asperi的答案),适用于那些寻求
ForEach
通用方法的人,我将视图抽象出来:DragRelocateDelegate
基本上保持不变,尽管我使它更通用、更安全:最后是实际用法:
6mw9ycah3#
还有一些额外的问题提出了上述优秀的解决方案,所以这里是我可以想出1月1日与宿醉(即道歉,因为不善于雄辩):
1.如果拾取网格项并释放它(取消),则不会重置视图
我添加了一个bool来检查视图是否已经被拖动过,如果没有,那么它就不会在第一时间隐藏视图。这是一个小技巧,因为它并没有真正重置,它只是推迟隐藏视图,直到它知道你想拖动它。也就是说,如果你拖动得非常快,你可以在隐藏视图之前看到它。
1.如果将网格项拖到视图之外,则不会重置视图
这个问题已经通过添加dropOutside委托得到了部分解决,但是SwiftUI不会触发它,除非你有一个背景视图(比如一个颜色),我认为这引起了一些混乱。因此我添加了一个灰色背景来说明如何正确触发它。
希望这对任何人都有帮助:
k5hmc34c4#
这里是如何实现on drop部分的。但是请记住,如果数据符合
UTType
,ondrop
可以允许从应用外部拖放内容。更多UTTypes。将onDrop示例添加到lazyVGrid。
创建DropDelegate以处理放置的内容和给定视图的放置位置。
此外,
performDrop
唯一真实的有用的参数是info.location
,它是放置位置的CGPoint,将CGPointMap到要替换的视图似乎是不合理的。我认为OnMove
是一个更好的选择,它可以使移动数据/视图变得轻而易举。我没有成功地在LazyVGrid
中使用OnMove
。由于
LazyVGrid
还在测试阶段,肯定会改变。我会放弃在更复杂的任务中使用。puruo6ea5#
目标:重新排序HStack中的项目
我试图弄清楚如何在SwiftUI for macOS中利用这个解决方案来拖动图标以重新排序一组水平项目。感谢@ramzesenok和@Asperi提供的整体解决方案。我在他们的解决方案中添加了一个CGPoint属性来实现所需的行为。请看下面的动画。
定义点
我在
dropEntered
、dropExited
和performDrop
的DropDelegate函数中使用过。作为完整的演示,我使用Playgrounds创建了一个gist
2ledvvac6#
我提出了一种在macOS上运行良好的不同方法。我使用
.gesture(DragGesture)
和一个helper类和修饰符来代替.onDrag
和.onDrop
。以下是辅助对象(只需将其复制到新文件):
现在,要在视图中使用它,您必须执行以下几项操作:
StateObject
的draggingManagercoordinateSpace
从draggingManager应用到容器(LazyVGrid)这样,draggingManager只在过程中修改数组的副本,您可以在拖动完成后更新原始数组。