未调用UIControl endTrackingWithTouch

时间:2014-09-19 17:16:06

标签: ios uicontrol

我有一个带有轻敲手势识别器的视图。此视图的子视图是我的自定义类的实例,它继承自UIControl。我遇到的问题是,UIControl子类有时会允许触摸事件传递到父视图,而不应该这样。

在UIControl子类中,我已经覆盖了这些函数(代码在Swift中)

override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool
{
    return true
}

override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool
{
    // The code here moves this UIControl so its center is at the touchpoint
    return true
}

override func endTrackingWithTouch(touch: UITouch,withEvent event: UIEvent)
{
    // Something important happens here!
}

如果用户在UIControl中向下触摸,在两个 X和Y方向上拖动控件,然后抬起屏幕,此系统就可以正常工作。在这种情况下,调用所有这三个函数,并发生“重要的事情”。

但是,如果用户触摸UIControl,在X方向上仅围绕 拖动控件,然后抬起屏幕,我们就遇到了问题。调用前两个函数,但是当触点从屏幕上抬起时,调用轻击手势识别器,并且不调用endTrackingWithTouch。

如何确保始终调用endTrackingWithTouch?

4 个答案:

答案 0 :(得分:3)

我以一种我认为是黑客的方式解决了这个问题,但考虑到UIGestureRecognizer的工作方式,我们别无选择。

发生的事情是,轻敲手势识别器正在取消控制的跟踪并注册轻击手势。这是因为当我水平拖动时,我恰好拖动了短距离,这被解释为一个轻敲手势。

在UIControl跟踪时,必须禁用点击手势识别器:

override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool
{
    pointerToSuperview.pauseGestureRecognizer()
    return true
}

override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool
{
    // The code here moves this UIControl so its center is at the touchpoint
    return true
}

override func endTrackingWithTouch(touch: UITouch,withEvent event: UIEvent)
{
    // Something important happens here!
    pointerToSuperview.resumeGestureRecognizer()
}

override func cancelTrackingWithEvent(event: UIEvent?)
{
    pointerToSuperview.resumeGestureRecognizer()
}

在superview的课程中:

pauseGestureRecognizer()
{
    tapGestureRecognizer.enabled = false
}

resumeGestureRecognizer()
{
    tapGestureRecognizer.enabled = true
}

这是有效的,因为我没有处理多点触控(我可以在跟踪UIControl的触摸时不接收点击触摸事件)。

理想情况下,控件不应该告诉视图暂停手势识别器 - 手势识别器不应该干扰控件的触摸开始!但是,即使将手势识别器的cancelsTouchesInView设置为false也无法阻止此操作。

答案 1 :(得分:3)

有一种方法可以解决这个非常独立的问题:实例化您自己的TapGestureRecognizer并将其附加到您的自定义控件,例如:在Objective-C中,

_tapTest = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
_tapTest.numberOfTapsRequired = 1;
[self addGestureRecognizer:_tapTest];

然后实现tapped操作处理程序来处理点击:

- (void)tapped:(UITapGestureRecognizer *)recognizer {...}

在我的情况下,我处理tappedendTrackingWithTouch:withEvent:相同;你的里程可能会有所不同。

这样,您可以在任何超级视图抢夺它之前获得点击,并且您不必担心控件背后的视图层次结构。

答案 2 :(得分:1)

在跟踪触摸时移动UIControl时,可能会取消其跟踪。尝试重写cancelTrackingWithEvent并查看是否是这种情况。如果您确实看到取消,则您必须在此控件的父层次结构中的某个位置以不动的方式跟踪您的触摸。

答案 3 :(得分:1)

我知道这已经过时了,但我遇到了同样的问题,检查你的一个超级视图是否有手势识别器,并在需要使用UIControl时停用它们。

我实际上已经将UIControl的超级视图更改为主窗口以避免这种冲突(因为它是在弹出窗口中)。