当在视图上同时使用.offset和.position Modifier决定最终位置时,究竟会发生什么?



这里我有这个问题,当我试图给一个视图的初始位置,然后用户可以使用拖动手势改变视图的位置到任何地方。虽然我已经通过只在视图上使用.position(x:y:)解决了这个问题,但一开始我想使用.position(x:y:)来给出初始位置,.offset(offset:)来同时使用手势使视图移动。现在,我真的只想更详细地知道,当我同时使用它们时(下面的代码)究竟发生了什么,这样我就可以解释在下面的视图中发生了什么。

我无法在下面的视图中解释的是:当我简单地在VStack框上拖动手势时,它按预期工作,VStack随着手指手势移动,然而,一旦手势结束并尝试在VStack上开始一个新的拖动手势,VStack框突然回到原始位置(就像加载代码时跳到原始位置),然后开始移动手势。请注意,手势像常规手势一样移动,但是VStack已经跳到不同的位置,所以它开始从不同的位置移动。这导致指尖不再位于VStack框的顶部,而是偏离了一段距离,尽管VStack的移动轨迹与拖动手势相同。

我的问题是:为什么.position(x:y:)修饰符似乎只在检测到的每个新拖动手势的开始时生效,但在拖动手势动作期间,.offset(offset:)似乎主导了主要运动,VStack停止在它被拖动到的地方。但是一旦新的拖动手势开启,VStack会突然跳转到原始位置。我只是无法理解这种行为是如何在时间轴上发生的。有人能提供一些见解吗?

请注意,我已经解决了这个问题,以实现我所需要的,现在只是为了了解当.position(x:y:).offset(offset:)同时使用时到底发生了什么,所以请避免一些建议,如。不要同时使用,谢谢。下面的代码在复制和粘贴之后应该是可运行的,如果不是,请原谅我犯的错误,因为我删除了几行以使其更清晰地重现问题。

import SwiftUI
struct ContentView: View {
var body: some View {
ButtonsViewOffset()
}
}
struct ButtonsViewOffset: View {
let location: CGPoint = CGPoint(x: 50, y: 50)
@State private var offset = CGSize.zero
@State private var color = Color.purple
var dragGesture: some Gesture {
DragGesture()
.onChanged{ value in
self.offset = value.translation
print("offset onChange: (offset)")
}
.onEnded{ _ in
if self.color == Color.purple{
self.color = Color.blue
}
else{
self.color = Color.purple
}
}
}

var body: some View {
VStack {
Text("Watch 3-1")
Text("x: (self.location.x), y: (self.location.y)")
}
.background(Color.gray)

.foregroundColor(self.color)
.offset(self.offset)
.position(x: self.location.x, y: self.location.y)
.gesture(dragGesture)

}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView()
}

}
}

您的问题与位置和偏移量的使用无关。它们实际上是同时工作的。Position设置视图的绝对位置,其中偏移量相对于绝对位置移动它。因此,您将注意到您的视图从屏幕上的位置(50,50)开始,然后您可以拖动它。一旦你放手,它就停在原地。到目前为止,一切顺利。然后你想再次移动它,它就会回到原来的位置。它这样做的原因是你将location设置为let常数的方式。

问题的根源在于您在没有意识到的情况下将offset的值添加到position。完成拖动后,offset将保留最后的值。但是,当您开始下一次拖动时,这些值又从(0,0)开始,因此偏移量被重置为(0,0),视图移动回原始位置。关键是您只需要使用.onEnded中的位置或更新偏移量。不要两者都用。这里你有一个设定的位置,并且没有保存偏移量。如何处理它取决于你移动视图的目的。

首先,使用.position():

struct OffsetAndPositionView: View {

@State private var position = CGPoint(x: 50, y: 50)
@State private var color = Color.purple

var dragGesture: some Gesture {
DragGesture()
.onChanged{ value in
position = value.location
print("position onChange: (position)")
}
.onEnded{ value in
if color == Color.purple{
color = Color.blue
}
else{
color = Color.purple
}
}
}

var body: some View {
Rectangle()
.fill(color)
.frame(width: 30, height: 30)
.position(position)
.gesture(dragGesture)
}
}
第二,使用.offset():
struct ButtonsViewOffset: View {
@State private var savedOffset = CGSize.zero
@State private var dragValue = CGSize.zero
@State private var color = Color.purple

var offset: CGSize {
savedOffset + dragValue
}
var dragGesture: some Gesture {
DragGesture()
.onChanged{ value in
dragValue = value.translation
print("dragValue onChange: (dragValue)")
}
.onEnded{ value in
savedOffset = savedOffset + value.translation
dragValue = CGSize.zero
if color == Color.purple{
color = Color.blue
}
else{
color = Color.purple
}
}
}
var body: some View {
Rectangle()
.fill(color)
.frame(width: 30, height: 30)
.offset(offset)
.gesture(dragGesture)
}
}
// Convenience operator overload
func + (lhs: CGSize, rhs: CGSize) -> CGSize {
return CGSize(width: lhs.width + rhs.width, height: lhs.height + rhs.height)
}

最新更新