I'm trying to build a view which can be swiped up and down. I'm not sure why the above behaviour is occurring in my code. The text is kind of jumping/stuttering. I want the view to be draggable while the text is animating without the animation being broken. Am I doing something I'm not supposed to do? Below is my code. Any tips would be highly appreciated.
struct ContentView: View {
@State var offset : CGFloat = 0
@State var time: String = "0.0"
let timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()
var body: some View {
VStack {
Spacer()
Text(String(time)).contentTransition(.numericText())
.onReceive(timer) { value in
withAnimation {
time = value.timeIntervalSince1970.minuteSecond // I have an extension for this.
}
}
Spacer()
}
.frame(maxWidth: .infinity)
.background(.red)
.offset(y: offset)
.gesture(swipeDownGesture)
}
}
extension ContentView {
var swipeDownGesture: some Gesture {
DragGesture()
.onChanged(onDrag(value:))
.onEnded(onSwipeDownEnded(value:))
}
func onDrag(value: DragGesture.Value){
let horizontalAmount = value.translation.width
let verticalAmount = value.translation.height
let isHorizontalSwipe = abs(horizontalAmount) > abs(verticalAmount)
let isSwipeDown = verticalAmount > 0
if isHorizontalSwipe {
let isSwipeRight = horizontalAmount > 0
if isSwipeRight {
// Ignore
} else {
// Ignore
}
}
else if isSwipeDown {
withAnimation {
offset = value.translation.height
}
}
}
func onSwipeDownEnded(value: DragGesture.Value){
withAnimation(.smooth(duration: 0.32, extraBounce: 0.22)) {
offset = 0
}
}
}
It seems that the contentTransition
doesn't work well in combination with changes to the position of the text on the screen.
It helps to add .geometryGroup()
to the Text
:
Text(String(time)).contentTransition(.numericText())
.onReceive(timer) { value in
// as before
}
.geometryGroup() // 👈 HERE
The modifier .drawingGroup()
also works. However, this modifier is more likely to cause side effects on other aspects of the display, so you probably want to use with caution.