Jayson
Jayson

Reputation: 1687

`touchesBegan:withEvent:` is delayed at left edge of screen

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?

Upvotes: 6

Views: 2507

Answers (5)

harryngh
harryngh

Reputation: 1859

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
        }
    }
}

Upvotes: 1

velkyel
velkyel

Reputation: 352

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.

Upvotes: 1

alasker
alasker

Reputation: 331

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;
}

Upvotes: 3

danialias
danialias

Reputation: 43

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.

Upvotes: 1

Purteeek
Purteeek

Reputation: 159

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

Upvotes: 7

Related Questions