I have a UIViewController subclass whose view has a complex hierarchy of descendant views, including UIButtons and a UISlider. I want to hide the controls after 5 seconds have passed without any user interaction. The 5 seconds part is easy: use a timer. I don't know of a general way to detect user interaction though.
My first thought was to override UIResponder's touchesBegan:withEvent: and touchesMoved:withEvent: in the UIViewController subclass, but those don't get called when the user taps a UIButton or drags the knob on the UISlider.
What I don't want to do is register for notifications from every control, if I can help it. I also don't want to mess with the UIWindow. Any other ideas?
I ended up creating a continuous gesture recognizer that recognizes when there is at least one touch. I added it to the UIViewController subclass's view and it works great! It took me a long time to realize that it needed both cancelsTouchesInView and delaysTouchesEnded set to false or else it would fail one way or another.
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
}
}
Add a UIGestureRecognizer to your UIViewController by calling setupTapGesture in viewDidLoad
- (void)setupTapGesture
{
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleVisibility)];
tapGesture.delegate = self;
[self.view addGestureRecognizer:tapGesture];
}
And then use this callback to detect touches from button, sliders (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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With