提问人:Gizmodo 提问时间:9/17/2023 最后编辑:Gizmodo 更新时间:9/18/2023 访问量:39
同一 UIView 中的两个 UIPanGestureRecognizer 同时调用
Two UIPanGestureRecognizers in the same UIView Invoked Simultaneously
问:
我希望两个同时工作。在中心上方滑动时,将调用 panGesture1,在中心下方滑动将调用 panGesture2。必须同时使用这两种方法。UIPanGestureRecognizers
UIView
let panGesture1 = UIPanGestureRecognizer()
let panGesture2 = UIPanGestureRecognizer()
self.panGesture1.addTarget(self, action: #selector(self.panGesture1Detected(_:)))
self.panGesture1.delegate = self
self.panGesture1.minimumNumberOfTouches = 1
self.panGesture1.maximumNumberOfTouches = 1
self.panGesture1.cancelsTouchesInView = false
self.panGesture1.delaysTouchesBegan = false
self.panGesture1.delaysTouchesEnded = true
self.panGesture1.requiresExclusiveTouchType = false
self.view.addGestureRecognizer(self.panGesture1)
self.panGesture2.addTarget(self, action: #selector(self.panGesture2Detected(_:)))
self.panGesture2.delegate = self
self.panGesture2.minimumNumberOfTouches = 1
self.panGesture2.maximumNumberOfTouches = 1
self.panGesture2.cancelsTouchesInView = false
self.panGesture2.delaysTouchesBegan = false
self.panGesture2.delaysTouchesEnded = true
self.panGesture2.requiresExclusiveTouchType = false
self.view.addGestureRecognizer(self.panGesture2)
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer == self.panGesture1 {
if gestureRecognizer.location(in: self.view).y < self.view.bounds.midY {
//Pangesture 1 is above the first half of view. So good.
return true
} else {
return false
}
}
else if gestureRecognizer == self.panGesture2 {
if gestureRecognizer.location(in: self.view).y > self.view.bounds.midY {
//Pangesture 2 is below the first half of view. So good.
return true
} else {
return false
}
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return true
}
本期
当第一次触摸平移时,它会识别出相应的平移手势。当第二次触摸下来时,它假定这是针对当前活动的平移手势。因此,基本上不可能同时激活两个平移手势。
轻松出路
在屏幕的一半上放置一个虚拟的 UIView,并在那里激活其中一个平移手势?
这甚至可能吗?
在同一视图中使用两个平移手势是否可能?
答:
1赞
Matic Oblak
9/18/2023
#1
我确实希望您得到一个使用 2 个手势识别器的答案。我自己玩过,但放弃了。
在您的视图上启用可能仍有可能,但我没有设法让它工作。isMultipleTouchEnabled
无论如何,平移手势是最容易自己实现的。他们绝对没有微调。您只需要跟踪拖拽。下面是一个使用触摸事件的非常简单的实现:
class CustomDragRecogniser {
private var currentTouch: UITouch?
// Control:
var mayBegin: (_ touch: UITouch) -> Bool = { _ in true }
var onBegin: (_ touch: UITouch) -> Void = { _ in }
var onDrag: (_ touch: UITouch) -> Void = { _ in }
var onEnded: (_ touch: UITouch) -> Void = { _ in }
// Input:
func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard currentTouch == nil else { return } // Already in progress
if let matching = touches.first(where: { mayBegin($0) }) {
currentTouch = matching
onBegin(matching)
}
}
func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let matching = touches.first(where: { $0 === currentTouch }) {
onDrag(matching)
}
}
func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let matching = touches.first(where: { $0 === currentTouch }) {
currentTouch = nil
onEnded(matching)
}
}
func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if let matching = touches.first(where: { $0 === currentTouch }) {
currentTouch = nil
onEnded(matching)
}
}
}
class SimultaneousGesturesViewController: UIViewController {
private var recognisers: [CustomDragRecogniser] = []
override func viewDidLoad() {
super.viewDidLoad()
view.isMultipleTouchEnabled = true
let topRecogniser = CustomDragRecogniser()
topRecogniser.mayBegin = { [weak self] touch in
guard let view = self?.view else { return false }
return touch.location(in: view).y < view.bounds.height*0.5
}
topRecogniser.onDrag = { [weak self] touch in
guard let view = self?.view else { return }
print("G1 moved to \(touch.location(in: view))")
}
let bottomRecogniser = CustomDragRecogniser()
bottomRecogniser.mayBegin = { [weak self] touch in
guard let view = self?.view else { return false }
return touch.location(in: view).y >= view.bounds.height*0.5
}
bottomRecogniser.onDrag = { [weak self] touch in
guard let view = self?.view else { return }
print("G2 moved to \(touch.location(in: view))")
}
recognisers = [topRecogniser, bottomRecogniser]
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
recognisers.forEach { $0.touchesBegan(touches, with: event) }
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
recognisers.forEach { $0.touchesMoved(touches, with: event) }
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
recognisers.forEach { $0.touchesEnded(touches, with: event) }
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
recognisers.forEach { $0.touchesCancelled(touches, with: event) }
}
}
您应该能够将其打包到视图或其他工具中,以屏蔽大部分代码或代码以实现可重用性。
评论
0赞
HangarRash
9/18/2023
为什么不子类?UIGestureRecognizer
0赞
Matic Oblak
9/18/2023
@HangarRash我只是没有尝试过。我很有可能会遇到与使用当前 UIPanGestureRecognizeniser 相同的问题。但是,如果不是,如果重新发明 UIPanGestureRecogniser 可以解决问题,那么我同意这是一种更好的方法。
2赞
HangarRash
9/18/2023
在我尝试提供解决方案之前,我正在等待 OP 用相关细节更新他们的问题。该问题目前是一个 XY 问题。
0赞
Gizmodo
9/18/2023
我修复了代码中的错误。
评论