我开始在 SwiftUI 中使用 DragGestures。我从一个简单的互联网示例开始,做了一些修改,一切正常。这是代码:
struct DragTest: View {
@State var viewState = CGSize.zero
var body: some View {
RoundedRectangle(cornerRadius: 30)
.fill(Color.blue)
.frame(width: 300, height: 400 + viewState.height)
.offset(x:0, y: viewState.height / 2)
.gesture(
DragGesture().onChanged { value in
viewState = value.translation
}
.onEnded { value in
withAnimation(.spring()) {
viewState = .zero
}
}
)
}
}
但是,如果我将框架高度调整更改为减去 viewstate.height 而不是添加,则代码将挂在预览中或处理器使用率 100% 的模拟器中。这看起来像是某种更新循环。
struct DragTest: View {
@State var viewState = CGSize.zero
var body: some View {
RoundedRectangle(cornerRadius: 30)
.fill(Color.blue)
.frame(width: 300, height: 400 - viewState.height)
.offset(x:0, y: viewState.height / 2)
.gesture(
DragGesture().onChanged { value in
viewState = value.translation
}
.onEnded { value in
withAnimation(.spring()) {
viewState = .zero
}
}
)
}
}
这是怎么回事?如果我不理解根本原因,我就不会在拖动手势方面走得太远。
我想我已经解决了这个问题,尽管解决问题的过程中出现的症状非常令人困惑。看来,如果您打算修改对象的几何形状(
.offset
不会这样做,但.frame
似乎会这样做),那么您需要在不同的坐标空间中执行DragGesture
,这不会在 DragGesture
期间更改大小。 (DragGesture
通常在什么坐标空间中操作?-我不知道,我找到的文档也没有说)。这是有效的代码,另外我尝试了几种变体。
struct DragTest3: View {
@State var trans = CGSize.zero
var body: some View {
Group {
RoundedRectangle(cornerRadius: 30)
.fill(Color.blue)
.frame(width: 300, height: 400 - trans.height)
.gesture(
DragGesture(coordinateSpace: .named("outer"))
.onChanged { value in
trans = value.translation
}
)
}
.frame(maxHeight: .infinity)
.coordinateSpace(name: "outer")
.border(.black)
}
}
互联网上最简单的
DragGesture
示例仅使用 .offset
修饰符,因此它们不会崩溃,我无法轻松找到不那么简单的示例。我的理论是,如果发生 DragGesture
的坐标空间正在改变大小,则代码可能会进入死亡螺旋。如果能在某处更详细地描述这些机制,那就太好了。
可以确认,我也像安德鲁一样修复了它。就我而言,我必须使用“gesture.location.x”和“gesture.location.y”而不是gesture.translation。
GeometryReader { geometry in
VStack {
ZStack {
// content...
}
.onHover { hovering in
isHovered = hovering
}
Text(name)
.foregroundColor(isHovered ? Color.black : Color.black.opacity(0.6))
}
.gesture(
DragGesture(minimumDistance: 0.10, coordinateSpace: .named("outer"))
.onChanged { gesture in
// animation code using gesture.location...
}
.onEnded { _ in
initialDragOffset = .zero
}
)
.onHover { hovering in
isHovered = hovering
}
.animation(Animation.spring(), value: isHovered)
.position(
x: geometry.size.width * style.left,
y: geometry.size.height * style.top
)
.frame(width: 40, height: 40)
.coordinateSpace(name: "outer")
}
}