我有以下问题。
我想要拖动
View
内的 ScrollView
。
现在,一切正常,拖动和滚动都发生了。但一旦我尝试同时执行这两项操作,dragOffset
似乎会保留下来,而不是重置到其初始位置。
更重要的是,
onEnded
的DragGesture
永远不会发生。我怎样才能阻止这种情况发生并将绿色Rectangle
重置到其初始位置?
拖动或滚动效果很好。
但是每当我两者都做时,就会发生这种情况。
struct ContentView: View {
@State private var dragOffset: CGSize = .zero
var body: some View {
ScrollView {
Rectangle()
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.foregroundColor(.green)
.offset(x: dragOffset.width)
}
.gesture(DragGesture()
.onChanged { value in
dragOffset = value.translation
}
.onEnded { value in
dragOffset = .zero
}
)
.animation(.default)
}
}
谢谢!
解决方案是使用
.updating
和 GestureState
代替。在手势因任何原因取消后,它会自动将偏移设置为其初始位置。
这样,我们就无需调用
onEnded
将其设置为初始位置,而当您通过滚动取消手势时,就不会发生这种情况。
代码:
struct ContentView: View {
@GestureState private var dragOffset: CGSize = .zero
var body: some View {
ScrollView {
Rectangle()
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.foregroundColor(.green)
.offset(x: dragOffset.width)
}
.gesture(DragGesture()
.updating($dragOffset) { value, state, transaction in
state = value.translation
}
)
.animation(.default)
}
}
注意:当然,您仍然可以拥有
onChanged
和 onEnded
块,只是不必再将偏移量设置为 .zero
,因为它会自动发生。
如果您要在
ObservableObject
类中使用它并希望发布您的dragOffset,那么这将是我找到的解决方案。
解决这个问题的最好方法是在后台添加几何阅读器。更改 geo.frame(in: .global).minY (滚动时)更新偏移量。此方法使用少量处理(我发现 CPU 使用率增加了约 2%)。
在视图中的某处添加以下代码:
.background(Group{
GeometryReader{ geo in
HStack{
}
.onChange(of: geo.frame(in: .global).minY) { _ in
// update the offset
}
}
}
对我来说,我遇到了一个问题,我需要在以垂直 ScrollView 作为父级的视图中水平滚动。当我意识到当滚动视图接管时它没有回到“结束”位置时,问题就出现了。
为了解决这个问题,我实现了一个 GeometryReader 来监听整个视图的全局位置。如果
y
原点改变,它应该回到“结束”位置。
ScrollView {
Content()
.gesture(
DragGesture(
minimumDistance: 10,
coordinateSpace: .global
)
.onChanged(handleChange)
.onEnded(handleEnded)
)
.background {
GeometryReader { geometry in
Color.clear
.onChange(of: geometry.frame(in: .global).origin.y) { _ in
handleEnded()
}
}
}
}
我认为
scrollView
有自己的手势,例如UIScrollView中的UIScrollViewPanGestureRecognizer
,在DragGesture
上添加scrollView
会混淆它。
你可以像这样改变你的代码:
var body: some View {
ScrollView {
Rectangle()
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.foregroundColor(.green)
.offset(x: dragOffset.width, y: dragOffset.height)
.gesture(DragGesture()
.onChanged { value in self.dragOffset = value.translation }
.onEnded { value in self.dragOffset = .zero }
)
}
.animation(.default)
}
我觉得效果很好。