SwiftUI:手势和偏移未按预期工作
SwiftUI: Gesture and Offset Are Not Working As Intended
我正在使用偏移量和手势修改器在屏幕上移动一个圆圈。当我使用这段代码时,一切都按预期工作:
import SwiftUI
struct MovingCircle: View {
@State private var dragged = CGSize.zero
var body: some View {
Circle()
.offset(x: self.dragged.width)
.frame(width: 20, height: 20)
.gesture(DragGesture()
.onChanged{ value in
self.dragged = value.translation
}
.onEnded{ value in
self.dragged = CGSize.zero
}
)
}
}
但是,我不想在onEnded 时将圆重置到原来的位置。我希望它留在原地,然后在拖动时再次移动。当我使用下面的代码时,我失去了在重新拖动时再次移动圆圈的能力,它仍然在原地:
import SwiftUI
struct MovingCircle: View {
@State private var dragged = CGSize.zero
var body: some View {
Circle()
.offset(x: self.dragged.width)
.frame(width: 20, height: 20)
.gesture(DragGesture()
.onChanged{ value in
self.dragged = value.translation
}
.onEnded{ value in
self.dragged = value.translation
}
)
}
}
这是什么原因,是我遇到了什么错误还是我编码不正确?
首先,理解问题,在.frame()
修饰符上加一个.border(Color.red)
:
.frame(width: 20, height: 20).border(Color.red)
您会看到,当点移动时,它的框架保持原位。这就是为什么稍后,它不会响应手势。 "tappable" 区域不再与点匹配。而且因为内容区现在是空的,所以不再是"tappable".
要使框随点移动,请颠倒顺序。 .offset()
应该稍后出现:
.frame(width: 20, height: 20).border(Color.red)
.offset(x: self.dragged.width)
最后,您会看到在每次 .onEnded()
之后,整个事情都会重置。解决它的一种方法是累积您在之前的手势中拖动了多少:
struct MovingCircle: View {
@State private var dragged = CGSize.zero
@State private var accumulated = CGSize.zero
var body: some View {
Circle()
.frame(width: 20, height: 20).border(Color.red)
.offset(x: self.dragged.width)
.gesture(DragGesture()
.onChanged{ value in
self.dragged = CGSize(width: value.translation.width + self.accumulated.width, height: value.translation.height + self.accumulated.height)
}
.onEnded{ value in
self.dragged = CGSize(width: value.translation.width + self.accumulated.width, height: value.translation.height + self.accumulated.height)
self.accumulated = self.dragged
}
)
}
}
Swift 5.x iOS 13
一个不太优雅的解决方案,如果你不想看到被拖动的对象;您只想能够拖动它;如果你有很多事情要做并且你想节省 CPU.
可能更有意义
显然你需要为它找到一个比绝对零更好的起始位置。
import SwiftUI
var intern:CGPoint = CGPoint(x:0,y:0)
enum DragState {
case inactive
case dragging(translation: CGSize)
}
struct ContentView: View {
@State var position:CGPoint = CGPoint(x:0,y:0)
@GestureState private var dragState = DragState.inactive
var body: some View {
ZStack {
Circle()
.frame(width: 24, height: 24, alignment: .center)
}.offset(x: self.dragOffset.width, y: self.dragOffset.height)
.gesture(DragGesture(coordinateSpace: .global)
.updating($dragState, body: { (drag, state, translation)
intern = drag.location
})
.onEnded { ( value ) in
self.position = intern
}
).position(position)
}
}
我正在使用偏移量和手势修改器在屏幕上移动一个圆圈。当我使用这段代码时,一切都按预期工作:
import SwiftUI
struct MovingCircle: View {
@State private var dragged = CGSize.zero
var body: some View {
Circle()
.offset(x: self.dragged.width)
.frame(width: 20, height: 20)
.gesture(DragGesture()
.onChanged{ value in
self.dragged = value.translation
}
.onEnded{ value in
self.dragged = CGSize.zero
}
)
}
}
但是,我不想在onEnded 时将圆重置到原来的位置。我希望它留在原地,然后在拖动时再次移动。当我使用下面的代码时,我失去了在重新拖动时再次移动圆圈的能力,它仍然在原地:
import SwiftUI
struct MovingCircle: View {
@State private var dragged = CGSize.zero
var body: some View {
Circle()
.offset(x: self.dragged.width)
.frame(width: 20, height: 20)
.gesture(DragGesture()
.onChanged{ value in
self.dragged = value.translation
}
.onEnded{ value in
self.dragged = value.translation
}
)
}
}
这是什么原因,是我遇到了什么错误还是我编码不正确?
首先,理解问题,在.frame()
修饰符上加一个.border(Color.red)
:
.frame(width: 20, height: 20).border(Color.red)
您会看到,当点移动时,它的框架保持原位。这就是为什么稍后,它不会响应手势。 "tappable" 区域不再与点匹配。而且因为内容区现在是空的,所以不再是"tappable".
要使框随点移动,请颠倒顺序。 .offset()
应该稍后出现:
.frame(width: 20, height: 20).border(Color.red)
.offset(x: self.dragged.width)
最后,您会看到在每次 .onEnded()
之后,整个事情都会重置。解决它的一种方法是累积您在之前的手势中拖动了多少:
struct MovingCircle: View {
@State private var dragged = CGSize.zero
@State private var accumulated = CGSize.zero
var body: some View {
Circle()
.frame(width: 20, height: 20).border(Color.red)
.offset(x: self.dragged.width)
.gesture(DragGesture()
.onChanged{ value in
self.dragged = CGSize(width: value.translation.width + self.accumulated.width, height: value.translation.height + self.accumulated.height)
}
.onEnded{ value in
self.dragged = CGSize(width: value.translation.width + self.accumulated.width, height: value.translation.height + self.accumulated.height)
self.accumulated = self.dragged
}
)
}
}
Swift 5.x iOS 13
一个不太优雅的解决方案,如果你不想看到被拖动的对象;您只想能够拖动它;如果你有很多事情要做并且你想节省 CPU.
可能更有意义显然你需要为它找到一个比绝对零更好的起始位置。
import SwiftUI
var intern:CGPoint = CGPoint(x:0,y:0)
enum DragState {
case inactive
case dragging(translation: CGSize)
}
struct ContentView: View {
@State var position:CGPoint = CGPoint(x:0,y:0)
@GestureState private var dragState = DragState.inactive
var body: some View {
ZStack {
Circle()
.frame(width: 24, height: 24, alignment: .center)
}.offset(x: self.dragOffset.width, y: self.dragOffset.height)
.gesture(DragGesture(coordinateSpace: .global)
.updating($dragState, body: { (drag, state, translation)
intern = drag.location
})
.onEnded { ( value ) in
self.position = intern
}
).position(position)
}
}