![](/img/trans.png)
[英]How can I capture which direction is being panned using UIPanGestureRecognizer?
[英]How do I capture the point initially tapped in a UIPanGestureRecognizer?
我有一个应用程序,可以让用户在屏幕上跟踪线条。 我是通过在 UIPanGestureRecognizer 中记录点来实现的:
-(void)handlePanFrom:(UIPanGestureRecognizer *)recognizer
{
CGPoint pixelPos = [recognizer locationInView:rootViewController.glView];
NSLog(@"recorded point %f,%f",pixelPos.x,pixelPos.y);
}
这很好用。 但是,我对用户在开始平移之前点击的第一点非常感兴趣。 但是上面的代码只给了我在手势被识别为平移(与轻敲)之后发生的点。
从文档来看,似乎没有简单的方法可以确定 UIPanGestureRecognizer API 中最初点击的位置。 虽然在 UIPanGestureRecognizer.h 中,我发现了这个声明:
CGPoint _firstScreenLocation;
...这似乎是私人的,所以没有运气。 我正在考虑完全脱离 UIGestureRecognizer 系统,只是为了捕获那个初始点击的点,然后在我知道用户确实开始了 UIPanGesture 时再参考它。 不过,在走那条路之前,我想我会在这里问。
聚会迟到了,但我注意到上面没有真正回答这个问题,事实上有一种方法可以做到这一点。 您必须继承 UIPanGestureRecognizer 并包括:
#import <UIKit/UIGestureRecognizerSubclass.h>
无论是在你编写类的 Objective-C 文件中,还是在你的 Swift 桥接头中。 这将允许您按如下方式覆盖 touchesBegan:withEvent 方法:
class SomeCoolPanGestureRecognizer: UIPanGestureRecognizer {
private var initialTouchLocation: CGPoint!
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event)
initialTouchLocation = touches.first!.locationInView(view)
}
}
然后您的财产 initialTouchLocation 将包含您寻求的信息。 当然,在我的示例中,我假设触摸集中的第一个触摸是感兴趣的触摸,如果 maxNumberOfTouches 为 1,这是有道理的。您可能希望使用更复杂的方法来查找感兴趣的触摸。
编辑:斯威夫特 5
import UIKit.UIGestureRecognizerSubclass
class InitialPanGestureRecognizer: UIPanGestureRecognizer {
private var initialTouchLocation: CGPoint!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event)
initialTouchLocation = touches.first!.location(in: view)
}
}
您应该能够使用translationInView:
来计算起始位置,除非您在两者之间重置它。 获取触摸的翻译和当前位置,并使用它来找到触摸的起点。
@John Lawrence 说得对。
import UIKit.UIGestureRecognizerSubclass
class PanRecognizerWithInitialTouch : UIPanGestureRecognizer {
var initialTouchLocation: CGPoint!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event)
initialTouchLocation = touches.first!.location(in: view)
}
}
请注意,实例变量initialTouchLocation
不能是私有的,如果您想从子类实例(处理程序)访问它。
现在在处理程序中,
func handlePan (_ sender: PanRecognizerWithInitialTouch) {
let pos = sender.location(in: view)
switch (sender.state) {
case UIGestureRecognizerState.began:
print("Pan Start at \(sender.initialTouchLocation)")
case UIGestureRecognizerState.changed:
print(" Move to \(pos)")
你可以使用这个方法:
CGPoint point = [gesture locationInView:self.view];
在同一个 UIView 中放入这个方法。
//-----------------------------------------------------------------------
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint point = [[[event allTouches] anyObject] locationInView:self];
NSLog(@"point.x ,point.y : %f, %f",point.x ,point.y);
}
在此处的 UIGestureRecognizer 类参考中查找它: https : //developer.apple.com/library/ios/documentation/uikit/reference/UIGestureRecognizer_Class/Reference/Reference.html
我还注意到,当我尝试读取 UIPanGestureRecognizer 上的 shouldBegin 方法中的值时,我只能在用户稍微移动一点后(即当手势开始识别平移时)才能看到它的位置。 知道这个平移手势实际上从哪里开始是非常有用的,这样我就可以决定它是否应该识别。
如果你不想继承 UIGestureRecognizer 视图,你有两个选择:
如果您有其他手势(例如点击、双击等),那么您可能需要选项 2,因为延迟为 0 的长按手势识别器将导致其他手势无法正确识别。
如果您不关心其他手势,而只希望平底锅正常工作,那么您可以使用延迟为 0 的 UILongPressGestureRecognizer 并且更容易维护,因为您无需手动跟踪开始观点。
适合:简单
不利于:与其他手势处理程序配合良好
创建手势时,请确保将minimumPressDuration设置为0
。 这将确保您的所有委托方法(例如应该开始)将正确接收第一次触摸。
因为 UILongPressGestureRecognizer 是一个连续手势识别器(与离散手势识别器相反),所以您可以通过处理UIGestureRecognizer.State.changed属性来处理移动,就像使用 UIPanGestureRecognizer(它也是一个连续手势识别器)一样。 本质上,您正在组合这两种手势。
let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(gestureHandler(_:))
gestureRecognizer.minimumPressDuration = 0
适用于:与其他手势识别器配合使用
不利于:保存开始状态需要更多的努力
步骤:
首先,您需要注册为委托并监听 shouldReceiveTouch 事件。
一旦发生这种情况,将触摸点保存在某个变量中(而不是手势点!)。
当需要决定是否真的要开始手势时,请阅读此变量。
var gestureStartPoint: CGPoint? = nil
// ...
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(gestureHandler(_:))
gestureRecognizer.delegate = self
// ...
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
gestureStartPoint = touch.location(in: self)
return true
}
警告:请务必阅读touch.location(in: self)
而不是gestureRecognizer.location(in: self)
因为前者是准确获取起始位置的唯一方法。
你现在可以在任何你想要的地方使用gestureStartPoint
,比如应该开始:
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
return isValidStartPoint(gestureStartPoint!)
}
您可以使用 UIGestureRecognizerStateBegan 方法。 这是有关 UIGestureRecognizer 类的 Apple 文档的链接。
哇,晚了几年......我遇到了这个问题,但用静态变量解决了它:
- (IBAction)handleGesture:(UIPanGestureRecognizer *)recog {
CGPoint loc = [recognizer locationInView:self.container];
static CGFloat origin = 0.0f;
switch (recognizer.state) {
case UIGestureRecognizerStateBegan:
origin = loc.x;
break;
case UIGestureRecognizerStateChanged:
case UIGestureRecognizerStatePossible:
// origin is still set here to the original touch point!
break;
case UIGestureRecognizerStateEnded:
break;
case UIGestureRecognizerStateFailed:
case UIGestureRecognizerStateCancelled:
break;
}
}
该变量仅在识别器状态为 UIGestureRecognizerBegan 时设置。 由于该变量是静态的,因此该值将保留到以后的方法调用中。
就我而言,我只需要 x 坐标,但如果需要,您可以将其更改为 CGPoint。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.