我正在开发一个自定义按钮组件,我需要使用拖动手势来设置自定义动画的各种状态,下面是我目前所在位置的简化代码。这里的问题是与按钮关联的操作在
.onEnded
阶段执行。这意味着用户可以将手指拖动到按钮之外,释放手指后将调用操作。我想检测手指是否在按钮的范围内,以及用户是否将其拖出,不执行操作并将点击状态切换为关闭,本质上是在手指不在按钮上时取消点击。
我尝试将
GeometryReader
包裹在我的 HStack
周围,但它报告了奇怪的值(比按钮的实际大小高得多的值),并且它使按钮组件扩展到全屏宽度和高度。
HStack {
Text("Sample Text")
}
.scaleEffect(taping ? 0.9 : 1)
.gesture(
DragGesture(minimumDistance: 0)
.onChanged { pressed in
taping.toggle()
}
.onEnded { pressed in
taping.toggle()
// Execute tap action here
}
)
我能够检测手指是否在元素之外或没有使用 GeometryReader,但无法弄清楚如何强制结束拖动手势。请尝试以下代码。
使用PreferenceKey获取视图的frame:
struct ButtonPreferenceData: Equatable {
let bounds: CGRect
}
struct ButtonPreferenceKey: PreferenceKey {
typealias Value = ButtonPreferenceData
static var defaultValue: ButtonPreferenceData = ButtonPreferenceData(bounds: CGRect())
static func reduce(value: inout ButtonPreferenceData, nextValue: () -> ButtonPreferenceData) {
value = nextValue()
}
}
使用 GeometryReader 检查拖动位置:
HStack {
Text("Sample Text")
.border(Color.black, width: 1)
}
.scaleEffect(taping ? 0.9 : 1)
.background(
GeometryReader { reader in
let frame = reader.frame(in: .local)
Rectangle()
.fill(Color.clear)
.preference(key: ButtonPreferenceKey.self, value: ButtonPreferenceData(bounds: frame))
}
)
.onPreferenceChange(ButtonPreferenceKey.self) { value in
bounds = value.bounds
print("\(bounds)")
}
.gesture(
DragGesture(minimumDistance: 0)
.onChanged { pressed in
if bounds.contains(pressed.location) {
print("Inside")
} else {
print("Outside")
}
taping = true
}
.onEnded { _ in
taping = false
}
)