ios - SwiftUI DragGesture onEnded 在某些情况下不会触发
问题描述
在我的应用程序中,我有一个可以向左或向右拖动的可滑动卡片视图。
当用户向左或向右拖动卡片时,卡片的水平偏移会更新。当用户释放拖动时,卡片会移出屏幕(向左或向右,取决于拖动方向),或者如果水平偏移没有超过阈值,卡片会回到初始位置。
它工作得很好,但是如果用户在拖动时用另一根手指触摸卡片视图,然后将他/她的手指从屏幕上移开,卡片位置会冻结,它既不会离开屏幕也不会回到初始位置。我调试了代码,结果发现在这种情况下DragGesture().onEnded
事件不会触发。
我正在寻找有关如何检测这种情况的任何提示。
这是代码:
如果我有类似isTouchingScreen
状态的东西,我将能够解决这个问题。
编辑:这是问题表现出来的一个最小示例。
import SwiftUI
struct ComponentPlayground: View {
@State private var isDragging: Bool = false
@State private var horizontalOffset: CGFloat = .zero
var background: Color {
if abs(horizontalOffset) > 100 {
return horizontalOffset < 0 ? Color.red : Color.green
} else {
return Color.clear
}
}
var body: some View {
GeometryReader { geometry in
Color.white
.cornerRadius(15)
.shadow(color: Color.gray, radius: 5, x: 2, y: 2)
.overlay(background.cornerRadius(15))
.rotationEffect(.degrees(Double(horizontalOffset / 10)), anchor: .bottom)
.offset(x: horizontalOffset, y: 0)
.gesture(
DragGesture()
.onChanged { gesture in
self.isDragging = true
self.horizontalOffset = gesture.translation.width
}
.onEnded { gesture in
self.isDragging = false
if abs(horizontalOffset) > 100 {
withAnimation {
self.horizontalOffset *= 5
}
} else {
withAnimation {
self.horizontalOffset = .zero
}
}
}
)
.frame(width: 300, height: 500)
}
}
}
struct ComponentPlayground_Previews: PreviewProvider {
static var previews: some View {
VStack {
Spacer()
HStack(alignment: .center) {
ComponentPlayground()
}
.frame(width: 300, height: 500)
Spacer()
}
}
}
解决方案
由于 Apple 没有对此问题进行更新,因此我将分享解决此问题的方法。解决方法仍然不提供类似于 UIKit 中的 UIPanGesture 的拖动功能,但仍然......
首先,我创建了两个 GestureStates 变量并在 DragGesture 中不断更新它们:
@GestureState private var stateOffset: CGSize = CGSize.zero
@GestureState private var isGesturePressed: Bool = false
let dragGesture = DragGesture()
.updating($stateOffset) { value, gestureState, transaction in
gestureState = CGSize(width: value.translation.width, height: value.translation.height)
}
.updating($isGesturePressed) { value, gestureState, transaction in
gestureState = true
}
通过更新“isGesturePressed”(通过在手势处于活动状态时使其为真),我将知道手势是否实际被按下。当它按下时,我用 stateOffset 做我的动画代码:
SomeView()
.offset(someCustomOffset)
.gesture(dragGesture)
.onChange(of: stateOffset) { _ in
if isGesturePressed {
withAnimation { Your Animation Code here
}
} else {
withAnimation { Your Animation Code here for when the gesture is no longer pressed. This is basically my .onEnd function now.
}
}
正如我上面所说。它不会提供通常的用户体验(例如 Twitter 侧边菜单),导致我们的动画在正在进行的动画期间当另一个手指按下屏幕时立即结束。但至少它不再卡在中途。肯定有更优雅和更好的书面解决方法,但我希望它可以帮助某人。
推荐阅读
- javascript - arrayGroup 的角度反应形式错误的 patchValue
- path - 在android中使用路径重复平铺图像
- django - 基于多个条件的标签搜索
- c# - c# - 在 vs 2017 中导入 PCl 项目时,Xamarin 在 nuget 包中形成错误
- html - 如何在html中隐藏切换元素
- azure - Service Fabric - 可靠的字典加密模型
- android - 将短信正文传递给默认短信应用
- django - 在 django rest 框架中更新之前更改数据
- ios - kotlin native 无法导入 khttp
- java - 从字符串的 ArrayList 中删除存储在 Set 中的停用词