I want a circle to slowly scale down as long as the user keeps a finger on it. The scale should stop and reset to its default value of 1 when
- either a LongPressGesture is detected (finished), i.e. the user pressed long enough for it to fire
- or the gesture ended, i.e. the user lifted the finger
I implemented this as follows. When I keep the finger on the circle, it works as expected. But when I do a normal tap on the circle, it scales down continuously and never stops. Why is that and how can I fix it?
struct ContentView: View {
@State private var longPressTimer: Timer?
@State private var longPressDuration: TimeInterval = 0
private var gesture: some Gesture {
LongPressGesture()
.onChanged { isPressing in
print("changed")
if isPressing {
longPressTimer = Timer.scheduledTimer(withTimeInterval: 1/25, repeats: true) { timer in
longPressDuration += timer.timeInterval
}
} else {
reset()
}
}
.onEnded { _ in
print("ended")
reset()
}
}
var body: some View {
Circle()
.foregroundColor(.red)
.scaleEffect(1 - longPressDuration/5)
.gesture(gesture)
}
private func reset() {
longPressDuration = 0
longPressTimer?.invalidate()
longPressTimer = nil
}
}
When I only tap and immediately lift the finger, ended is never printed to the console and changed is only printed once (when the gesture begins). When I long-press, it prints
changed
ended
as expected.