在 SwiftUI 视图上为 DragGesture 的 predictedEndTranslation 设置动画
Animating to the predictedEndTranslation of a DragGesture on a SwiftUI view
我想在 DragGesture
的预测位置放置一个视图,这就是我在 .gestureEnded
闭包中所做的,将更改包装在 withAnimation
块中。然而,当我在实时视图中尝试时,变化不是动画的。
这是框架的错误还是我做错了什么?
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()
}
}
好像translateEffect
不能做动画。这是有道理的,因为 CGAffineTransform 不符合 Animatable
,所以这可能是预期的。幸运的是,你仍然可以使用 .offset(x: 0, y: ty)
.
这对你有用吗?
请注意,某些动画(例如这个动画)在 Xcode 实时预览中不起作用。您需要在设备或模拟器上 运行 它。
SwiftUI/iOS 13.4 效果的示例实现,还修复了重复拖动时视图跳动的问题。
诀窍是使用 @GestureState
跟踪正在进行的手势并单独保持整体状态变化,使用 .offset
修饰符应用变化:
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()
}
}
我想在 DragGesture
的预测位置放置一个视图,这就是我在 .gestureEnded
闭包中所做的,将更改包装在 withAnimation
块中。然而,当我在实时视图中尝试时,变化不是动画的。
这是框架的错误还是我做错了什么?
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()
}
}
好像translateEffect
不能做动画。这是有道理的,因为 CGAffineTransform 不符合 Animatable
,所以这可能是预期的。幸运的是,你仍然可以使用 .offset(x: 0, y: ty)
.
这对你有用吗?
请注意,某些动画(例如这个动画)在 Xcode 实时预览中不起作用。您需要在设备或模拟器上 运行 它。
SwiftUI/iOS 13.4 效果的示例实现,还修复了重复拖动时视图跳动的问题。
诀窍是使用 @GestureState
跟踪正在进行的手势并单独保持整体状态变化,使用 .offset
修饰符应用变化:
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()
}
}