6

I'm experiencing an issue where the first call to touchesBegan:withEvent: on a UIView or UIViewController is delayed when you touch on the left edge of the screen. This seems to be a new issue with iOS 10, and only happens on devices with 3D Touch (iPhone 6s and newer). In fact, if you disable 3D Touch in General->Accessibility, the issue goes away.

However, the issue doesn't seem to happen when you use UIGestureRecognizers. My workaround at the moment is to create a UIGestureRecognizer subclass that overrides the touches* methods and forwards them to my old implementation.

Is this just a bug or is there a way to get rid of the delay?

Jayson
  • 1,689
  • 14
  • 26

5 Answers5

7

try adding this to the viewdidappear method. this might fix the issue. it happened with me as well but i got this code from stack overflow that fixed my issue. hope it helps you too

let window = view.window!
let gr0 = window.gestureRecognizers![0] as UIGestureRecognizer
let gr1 = window.gestureRecognizers![1] as UIGestureRecognizer
gr0.delaysTouchesBegan = false
gr1.delaysTouchesBegan = false
Purteeek
  • 159
  • 4
  • 2
    Hm I see how that would solve the immediate issue but messing with the system gesture recognizers seems like it'll cause more problems down the line – Jayson Oct 02 '16 at 16:59
  • I did some more investigating and this seems like the best solution for now. These gestures recognizers are instances of `_UISystemGestureGateGestureRecognizer` and seem to be mainly used to make sure your app interacts nicer with system gestures like control center or 3D touch app switching. For the left edge, I believe the delay was added to prevent accidental app interaction when the user tries to switch apps, but in my case I need responsive touches on the left edge and it's alright if the touches trigger when the users tries to switch apps. – Jayson Oct 02 '16 at 18:22
3

Like danialias I'm working on a game. The solution I found (currently working, tested on an iPhone with 3D Touch enabled, where this was a real issue up to this point..) works for both games/apps:

It seems that UITapGestureRecognizer doesn't suffer from this delay, so simply add one to your view, and use it to handle taps.

In my game, I store touches and handle them on every interval update, so I overrode

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

and there I stored the UITouch instance and returned NO.

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    [self.touches addObject:touch];
    return NO;
}
alasker
  • 309
  • 5
  • 18
1

Purteeek solution seems to work nicely in my case too. This is an objective-C implementation for SpriteKit:

- (void)didMoveToView:(SKView *)view {

    UIGestureRecognizer* gr0 = view.window.gestureRecognizers[0];
    UIGestureRecognizer* gr1 = view.window.gestureRecognizers[1];

    gr0.delaysTouchesBegan = false;
    gr1.delaysTouchesBegan = false;

}

This doesn't mess with other gesture recognizers, and the system 3D Touch still works fine. I wonder why this is not the default behavior.

danialias
  • 43
  • 5
1

in iOS 13.2. it seems that trick is not possible:

[Warning] Trying to set delaysTouchesBegan to NO on a system gate gesture
recognizer - this is unsupported and will have undesired side effects

Looks like the only solution is disable 3D touch in Settings.

velkyel
  • 352
  • 4
  • 13
0

This works for me

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if let window = view.window,
        let recognizers = window.gestureRecognizers {
        recognizers.forEach { r in
            r.delaysTouchesBegan = false
            r.cancelsTouchesInView = false
            r.isEnabled = false
        }
    }
}
harryngh
  • 1,789
  • 1
  • 13
  • 6