UIPanGestureRecognizer 起点已关闭

Posted

技术标签:

【中文标题】UIPanGestureRecognizer 起点已关闭【英文标题】:UIPanGestureRecognizer starting point is off 【发布时间】:2010-05-18 21:50:48 【问题描述】:

我有一个 UIView,它附加了一个 UIPanGestureRecognizer 手势工作正常,除了起点不是平移第一次开始的地方,它通常在 x 和 y 坐标中偏离 5 到 15 个像素。不幸的是方差不一致,似乎与平移运动发生的速度有关。

为了验证触摸是否正确发送,我向子视图添加了一个 touchesBegan 方法,它接收到正确的起点,但手势在其开始阶段没有提供相同的点。下面是我日志中的一些示例“线起点”是从手势识别器接收到的第一个点。

touchesBegan got point 617.000000x505.000000
Line start point at 630.000000x504.0000001
touchesBegan got point 403.000000x503.000000
Line start point at 413.000000x504.000000 
touchesBegan got point 323.000000x562.000000
Line start point at 341.000000x568.000000

以前有人见过这个问题吗?

关于如何在不必实现全新的 UIGestureRecognizer 的情况下解决该问题的任何想法?

【问题讨论】:

这能回答你的问题吗? How do I capture the point initially tapped in a UIPanGestureRecognizer? 【参考方案1】:

您可以使用手势识别器的委托方法检测手势的初始触摸位置

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch

【讨论】:

我遇到了这个问题所描述的确切问题,这帮助我以正确的方式解决了它(恕我直言)。 CGPoint 起始位置 = [触摸 locationInView:self]; // 在委托方法中工作 这很好用。另一个使用 UILongPressGestureRecognizer 并且不需要存储起点的选项。两种解决方案各有利弊。有关详细信息,请参阅answer here。【参考方案2】:
  CGPoint beg = [panRecognizer locationInView:_scrollView];
  CGPoint trans = [panRecognizer translationInView:_scrollView];
  CGPoint firstTouch = CGPointSubtract(beg, trans);

将此代码放在 UIGestureRecognizerStateBegan 案例中

【讨论】:

【参考方案3】:

documentation 表示当手指“移动到足以被视为平移”时开始平移手势。这种移动是为了区分按下和拖动,因为用户的手指在尝试按下而不拖动时可能会移动一点。

我认为这是您看到的第一个接触点和第一个被视为拖动部分的点之间的区别。

【讨论】:

即使通过扩展 UIGestureRecognizer 创建自己的手势识别器也会出现问题,但起点与 touchesBegan 方法不同。我向苹果提交了一个错误。 嗯,我不确定我是否理解。如果您正在实现自己的 UIGestureRecognizer,您不会在 touchesBegan 中定义自己的起点吗? @Douglas - 你有没有找到解决这个问题的方法? @CoDEFRo 我没有比这更进一步,也许 Cory 有。 @Cory Powers - 运气好能解决这个问题吗?【参考方案4】:

是的,区别在于手势识别器在激活之前会等待一段未确定的移动距离。您可以做的是创建自己的 UIPanGestureRecognizer 并在 touchesMoved 覆盖方法中将状态设置为 UIGestureRecognizerStateChanged。

注意:我使用了 touhcesMoved 而不是 touchesBegan,因为我希望它在用户触摸移动时启动,而不是立即启动。

以下是执行此操作的自定义手势识别器的一些示例代码:

#import "RAUIPanGestureRecognizer.h"

@implementation RAUIPanGestureRecognizer 


#pragma mark - UIGestureRecognizerSubclass Methods

- (void)reset
     [super reset ]; 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
     [super touchesBegan:touches withEvent:event ]; 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
     
        [self setState:UIGestureRecognizerStateChanged ];
        [super touchesMoved:touches withEvent:event ]; 
    

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
     [super touchesEnded:touches withEvent:event ]; 

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
     [super touchesCancelled:touches withEvent:event ]; 


@end

【讨论】:

工作就像一个魅力。不过不要忘记在类实现的开头#import 【参考方案5】:

要解决此问题,您可以尝试在手势识别器开始时重置翻译点。例如,像这样开始您的操作方法:

- (void)panGesture:(UIPanGestureRecognizer *)recognizer;

    if ( recognizer.state == UIGestureRecognizerStateBegan )
    
        CGPoint point = ...; // The view's initial origin.
        UIView *superview = [recognizer.view superview];
        [recognizer setTranslation:point inView:superview];
    

【讨论】:

【参考方案6】:

起点改变原因正如@Douglas所说:

当手指移动到足以被视为平移时,平移手势开始。

并且起点和平移都是在识别平移手势后计算的。

我使用以下方式来获取“真正的”起点:

对于具有平移手势的视图,覆盖-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 方法,并存储“真实”起点供以后使用:

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 
    [super touchesBegan:touches withEvent:event];
    self.touchStartPoint = [[[touches allObjects] firstObject] locationInView:self];

【讨论】:

以上是关于UIPanGestureRecognizer 起点已关闭的主要内容,如果未能解决你的问题,请参考以下文章

UIPanGestureRecognizer 碰撞

如何在父视图中限制 UIPanGestureRecognizer

UIPanGestureRecognizer 干扰滚动

未调用 iOS 13 UIPanGestureRecognizer 选择器

Swift:获取 UIPanGestureRecognizer 的目标

当对象移动到某个帧时如何停止 UIPanGestureRecognizer