我有一个项目视图,上面有一个
.simultaneousGesture(DragGesture())
修饰符,用于处理在画布周围拖动项目并更新其 x 和 y 位置。我还想添加一个 .onDrag
修饰符来处理不同视图之间的拖放项目。但这两者互相干扰。
我尝试在手势之前和之后放置
.onDrag
,但这两个位置都没有解决我的问题。
如果 .onDrag
放置在 .simultaneousGesture
之前,则 .onDrag
事件会按预期触发,.simultaneousGesture
也会触发,但仅限于前几次更新。如果放在后面,则仅识别 .simultaneousGesture
。
下面是视图的代码,下面我附加了拖动 FileView 后控制台输出的屏幕截图。
import Foundation
import SwiftUI
struct FileView: View {
@ObservedObject var form: Forms.File
@State private var firstClick: Bool = false
@State private var mousedown: Bool = false
@State private var initialDragOffset = CGSize.zero
@State private var hovering: Bool = false
@ObservedObject private var windowSize = WindowSize.shared
var body: some View {
HStack {
Image(systemName: "doc.fill")
.resizable()
.scaledToFit()
.frame(width: 17, height: 17)
.aspectRatio(contentMode: .fit)
.scaleEffect(x: 1, y: mousedown ? 0.8 : 1)
.foregroundColor(form.isSelected ? Color.red : Color.black)
.frame(width: 15, height: 15)
Text(form.name)
}
.frame(height: 30)
.onHover { hovering in
self.hovering = hovering
}
.padding(.leading, 8)
.padding(.trailing, 8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(form.isSelected ? Color.red : Color.clear, lineWidth: 1)
)
.position(
x: windowSize.width * form.canvasPosition.x,
y: windowSize.height * form.canvasPosition.y
)
.onDrag {
print("DRAGGING")
return NSItemProvider(object: form.path as NSString)
}
.simultaneousGesture(
DragGesture(minimumDistance: 0.10)
.onChanged { gesture in
if initialDragOffset == .zero {
let initialX = windowSize.width * form.canvasPosition.x
let initialY = windowSize.height * form.canvasPosition.y
initialDragOffset = CGSize(width: gesture.location.x - initialX,
height: gesture.location.y - initialY)
}
let newX = (gesture.location.x - initialDragOffset.width) / windowSize.width
let newY = (gesture.location.y - initialDragOffset.height) / windowSize.height
form.updatedAt = Int(Date().timeIntervalSince1970)
form.canvasPosition.x = newX
form.canvasPosition.y = newY
print(newX, newY)
}
.onEnded { _ in
initialDragOffset = .zero
}
)
.onLongPressGesture(minimumDuration: 0.01, pressing: { isPressing in
if isPressing {
withAnimation(.easeInOut(duration: 0.1)) {
mousedown = true
}
} else {
if firstClick {
form.open()
} else {
firstClick = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
firstClick = false
}
}
if(form.isSelected) {
mousedown = false
} else {
withAnimation(Animation.interpolatingSpring(mass: 2.0, stiffness: 80, damping: 8, initialVelocity: 0).speed(6)) {
mousedown = false
form.isSelected.toggle()
}
}
}
}){}
}
}
正如您在输出中看到的,
onChanged
在 .onDrag
事件触发之前打印一次,之后打印一次,但当我继续拖动时,不会再打印一次。有什么方法可以让这两个修饰符协调工作吗?
注意:我尝试过,但我不知道如何嵌入图像而不是仅显示链接:(
组合 .onDrag 和 .simultaneousGesture 确实会引起冲突,因为这两种手势可能会干扰彼此的状态和识别。管理此问题的一种方法是创建一个自定义手势,该手势结合了拖放功能和位置更新逻辑的行为。以下是实现这一目标的方法:
自定义手势识别器:将拖放逻辑合并到单个手势识别器中。 状态管理:管理自定义手势中的状态,以确保两种功能可以共存。 以下是修改 FileView 来实现此目的的方法:
迅速 复制代码 进口基金会 导入 SwiftUI
结构FileView:视图{ @ObservedObject var 形式:Forms.File
@State private var firstClick: Bool = false
@State private var mousedown: Bool = false
@State private var initialDragOffset = CGSize.zero
@State private var hovering: Bool = false
@ObservedObject private var windowSize = WindowSize.shared
var body: some View {
HStack {
Image(systemName: "doc.fill")
.resizable()
.scaledToFit()
.frame(width: 17, height: 17)
.aspectRatio(contentMode: .fit)
.scaleEffect(x: 1, y: mousedown ? 0.8 : 1)
.foregroundColor(form.isSelected ? Color.red : Color.black)
.frame(width: 15, height: 15)
Text(form.name)
}
.frame(height: 30)
.onHover { hovering in
self.hovering = hovering
}
.padding(.leading, 8)
.padding(.trailing, 8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(form.isSelected ? Color.red : Color.clear, lineWidth: 1)
)
.position(
x: windowSize.width * form.canvasPosition.x,
y: windowSize.height * form.canvasPosition.y
)
.gesture(
DragGesture(minimumDistance: 0.10)
.onChanged { gesture in
if initialDragOffset == .zero {
let initialX = windowSize.width * form.canvasPosition.x
let initialY = windowSize.height * form.canvasPosition.y
initialDragOffset = CGSize(width: gesture.location.x - initialX,
height: gesture.location.y - initialY)
}
let newX = (gesture.location.x - initialDragOffset.width) / windowSize.width
let newY = (gesture.location.y - initialDragOffset.height) / windowSize.height
form.updatedAt = Int(Date().timeIntervalSince1970)
form.canvasPosition.x = newX
form.canvasPosition.y = newY
print(newX, newY)
}
.onEnded { _ in
initialDragOffset = .zero
}
)
.onDrag {
print("DRAGGING")
return NSItemProvider(object: form.path as NSString)
}
.onLongPressGesture(minimumDuration: 0.01, pressing: { isPressing in
if isPressing {
withAnimation(.easeInOut(duration: 0.1)) {
mousedown = true
}
} else {
if firstClick {
form.open()
} else {
firstClick = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
firstClick = false
}
}
if(form.isSelected) {
mousedown = false
} else {
withAnimation(Animation.interpolatingSpring(mass: 2.0, stiffness: 80, damping: 8, initialVelocity: 0).speed(6)) {
mousedown = false
form.isSelected.toggle()
}
}
}
}){}
}
} 解释 自定义手势:使用单个 DragGesture 并管理 .onChanged 和 .onEnded 闭包内的状态来处理拖动和位置更新。 状态管理:跟踪初始拖动偏移以正确计算新位置。 此设置确保 DragGesture 可以连续处理位置更新,并且 .onDrag 修改器可以处理拖放功能而不会相互干扰。 .onDrag 功能仅在拖动手势结束时触发,确保两个手势协调工作。