Closed kevmusic closed 2 years ago
hi @kevmusic . Yes, I remember something similar to this when you used a second finger to pull-down the Notification Center. SwiftUI doesn't call the onEnded
callback inside DragGesture
but I'll see if there's any workaround to this
Hi @fermoya!
Were you able to find a workaround?
Let me know, thanks!
Hi @kevmusic , unfortunately there's been no luck. I found a possible solution where I can update and observe changes in a GestureState
. According to this answer, the onEnded
method wouldn't be called but GestureState
should reset. I tried this but unfortunately it seems to not work as they say. I reported a bug but I've gotten no answer so far.
Here's a simple example that reproduces it:
import SwiftUI
struct ContentView: View {
@GestureState var offset: CGSize = .zero
var body: some View {
Text("Hello, world!")
.offset(offset)
.gesture(
DragGesture()
.updating($offset, body: { value, state, _ in
state = value.translation
})
)
}
}
It doesn't seem to happen as often, but it still happens:
It's very easy to be reproduced. Just tap with another finger while dragging between elements. See the video:
https://user-images.githubusercontent.com/3084606/160623643-b8091ec7-39a7-46a8-b0b8-def05d372a9d.mov
What is worse, changing pages with page.update(.next)
doesn't reset the offset. The only way to reset the offset is to drag again. It can't be done programmatically. I implemented this Reset
button which does it, but it uses some internal APIs. It's actually the onDragCancelled()
function from PagerContent
.
HStack {
Button("Prev") {
withAnimation {
page2.update(.previous)
}
}
Button("Reset") {
withAnimation {
page2.draggingOffset = 0
page2.lastDraggingValue = nil
page2.draggingVelocity = 0
page2.objectWillChange.send()
}
}
Button("Next") {
withAnimation {
page2.update(.next)
}
}
}
https://user-images.githubusercontent.com/3084606/160625979-4681b703-826e-403c-b9ec-8e692680c122.mp4
Question: can you make the onDragCancelled()
function publicly available via the Page
object? So that it could be called this way page.reset()
? This way I could implement some workarounds on my side.
@darecki you can't page.reset()
because what's the initial page
? For some might 0
, for some other people it might be different.
I don't think onDragCancelled
gets called. That's there for this specific case scenario #69 . In this issue, it doesn't work as the App is still active. The problem is the same, but #69 had a workaround
@fermoya probably name reset()
that I proposed was a bit unfortunate and you misunderstood my intentions. This function, whatever is named, is supposed to reset the dragging state, which is exactly what you do in onDragCancelled
.
I want to be able to call onDragCancelled
from the outside, which I indirectly did in this code snippet
Button("Reset") {
withAnimation {
page2.draggingOffset = 0
page2.lastDraggingValue = nil
page2.draggingVelocity = 0
page2.objectWillChange.send()
}
}
That is not possible now, as this API is internal and not public. I hope it is more clear now.
If I had this possibility to reset the carousel from my code, I could work around the problem this way:
Set up a new timer on each onDraggingChanged
(say 0.5 second).
Invalidate the timer on onDraggingEnded
If timer fires == no onDraggingEnded
callback received -> I assume the view got stuck and I programmatically reset the view.
As of now, I unfortunately can't do it this way.
@kevmusic @darecki apologies because this is something I've been testing in a simulator and not on a real device. Somehow I get different behaviors.
I've made a change that I think solves this issue. @darecki do you mind confirming this? It should be fixed in 2.3.3-beta.5
@fermoya yes, it fixes the issue on my end. Great job!
Steps to reproduce
https://user-images.githubusercontent.com/13948320/139624570-0529c135-0ba2-429f-8595-d12fe72692b8.mp4