I want to place a view at the predicted location of a DragGesture
, that's what I do in my .gestureEnded
closure, wrapping the change in a withAnimation
block. Yet, when I try it in the live view, the change isn't animated.
Is this a bug of the framework or am I doing something wrong?
struct ContentView: View {
@State var ty: CGFloat = 0
var dragGesture: some Gesture {
DragGesture()
.onChanged { theGesture in
self.ty = theGesture.translation.height
print("Changed")
}
.onEnded { theGesture in
print("Ended")
withAnimation(Animation.easeOut(duration: 3)) {
self.ty = theGesture.predictedEndTranslation.height
}
}
}
var body: some View {
VStack {
ForEach(1 ..< 5) { _ in
Color.red
.frame(minHeight: 20, maxHeight: 100)
.padding(0)
}
}
.transformEffect(.init(translationX: 0, y: ty))
.gesture(dragGesture)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
It seems translateEffect
cannot be animated. It kind of makes sense, since CGAffineTransform does not conform to Animatable
, so that might be as intended. Fortunately, you can still use .offset(x: 0, y: ty)
.
Will that work for you?
Note that some animations (like this one), do not work in Xcode Live Preview. You need to run it on a device or the simulator.
An example implementation of the effect for SwiftUI/iOS 13.4, also fixing the view jumping around when dragged repeatedly.
The trick is to use @GestureState
to keep track of the gesture in progress and to keep the overall state change separately, applying the changes with the .offset
modifier:
struct DragGestureView: View {
@GestureState var dragOffset = CGSize.zero
@State var offset: CGFloat = 0
var dragGesture: some Gesture {
DragGesture()
.updating($dragOffset) { value, state, _ in
state = value.translation
}
.onEnded { gesture in
// keep the offset already moved without animation
self.offset += gesture.translation.height
withAnimation(Animation.easeOut(duration: 3)) {
self.offset += gesture.predictedEndTranslation.height - gesture.translation.height
}
}
}
var body: some View {
VStack {
ForEach(1 ..< 5) { _ in
Color.red
.frame(minHeight: 20, maxHeight: 100)
}
}
.offset(x: 0, y: offset + dragOffset.height)
.gesture(dragGesture)
}
}
struct DragGestureView_Previews: PreviewProvider {
static var previews: some View {
DragGestureView()
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.