有没有一种通用的方法来通知所有触摸在 UIViewController 级别开始和移动?

Is there a general way to be notified of all touches began and moved at the UIViewController level?

我有一个 UIViewController 子类,其视图具有复杂的后代视图层次结构,包括 UIButton 和一个 UISlider。我想在没有任何用户交互的情况下 5 秒后隐藏控件。 5 秒部分很简单:使用计时器。不过,我不知道检测用户交互的一般方法。

我的第一个想法是在 UIViewController 子类中覆盖 UIRespondertouchesBegan:withEvent:touchesMoved:withEvent:,但是当用户点击UIButton 或拖动 UISlider 上的旋钮。

我不想做的是注册来自每个控件的通知,如果我能帮忙的话。我也不想弄乱 UIWindow。还有其他想法吗?

为什么不使用 UIGestureRecognizer?您可能必须为不同的可能交互类型(例如按住和滑动)设置几个不同的交互类型,但是您可以让所有这些交互类型都调用相同的函数来保持屏幕打开并重置计时器。

通过调用 viewDidLoad 中的 setupTapGesture 将 UIGestureRecognizer 添加到您的 UIViewController

- (void)setupTapGesture 
{
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleVisibility)];
    tapGesture.delegate = self;
    [self.view addGestureRecognizer:tapGesture];
}

然后使用此回调来检测来自按钮、滑块 (UIControl) 的触摸

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer    shouldReceiveTouch:(UITouch *)touch 
{
        //To ignore touches from Player Controls View
        if ([[touch.view superview] isKindOfClass:[UIControl class]]) 
        {
            return NO;
        }
        return YES;
}

我最终创建了一个连续手势识别器,它可以识别至少一次触摸。我将它添加到 UIViewController 子类的视图中,效果很好!我花了很长时间才意识到它需要将 cancelsTouchesInViewdelaysTouchesEnded 都设置为 false 否则它会以某种方式失败。

class TouchDownGestureRecognizer: UIGestureRecognizer {

    override init(target: AnyObject, action: Selector) {
        super.init(target: target, action: action)

        cancelsTouchesInView = false
        delaysTouchesEnded = false
    }

    override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
        state = .Began
    }

    override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {
        if numberOfTouches() - touches.count == 0 {
            state = .Ended
        }
    }

    override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
        if numberOfTouches() - touches.count == 0 {
            state = .Cancelled
        }
    }

    override func shouldBeRequiredToFailByGestureRecognizer(otherGestureRecognizer: UIGestureRecognizer!) -> Bool {
        return false
    }

    override func shouldRequireFailureOfGestureRecognizer(otherGestureRecognizer: UIGestureRecognizer!) -> Bool {
        return false
    }

    override func canPreventGestureRecognizer(preventedGestureRecognizer: UIGestureRecognizer!) -> Bool {
        return false
    }

    override func canBePreventedByGestureRecognizer(preventingGestureRecognizer: UIGestureRecognizer!) -> Bool {
        return false
    }

}