2
votes

I'm trying to override the "swipe down from the top of the screen" gesture (the same gesture that opens the Notification Center) in my iOS app.

From my understanding, the correct way to do so is to override the preferredScreenEdgesDeferringSystemGestures() method on the view controller and use the UIScreenEdgePanGestureRecognizer to handle the gesture.

In my case, the default system gesture is successfully blocked (Notification Center is not opened, only the gray indicator appears at the top of the screen), but the gesture recognizer is not triggered. Here is the code for the view controller:

class ViewController: UIViewController {

    override func preferredScreenEdgesDeferringSystemGestures() -> UIRectEdge {
        return .top
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let gestureRecognizer = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(swipeFromTop))
        gestureRecognizer.edges = .top
        view.addGestureRecognizer(gestureRecognizer)
    }

    @objc func swipeFromTop() {
        print("swipe from top") // not printed
    }
}

I tried the same thing for the "swipe up from the bottom of the screen" gesture and that works as expected (Control Center is not opened and the gesture recognizer is triggered).

I'm testing on iPhone 7 running iOS 11.4.

1
You can implement delegate callbacks of gestureRecognizer to debug what's going on - e.g. if it receives touches, if it "begins" and if it fails.Eugene Dudnyk
@DisableR thanks for the idea, I tried implementing all of the delegate methods described here, but none of them are called.denjiz
is your ViewController inside of navigation controller?Eugene Dudnyk
@DisableR No, it's just a UIViewController in a UIWindow (the default setup you get with "Single View App")denjiz
I just created "single view" project and added your code - on iPhone 8 Plus simulator swipeFromTop is being called, if I start to swipe a bit below the status bar.Eugene Dudnyk

1 Answers

1
votes

To make a "swipe from top" gesture work, you need to hide the status bar by setting your UIViewController's prefersStatusBarHidden property to return true.

If your UIViewController instance is embedded in a UINavigationController, you also need to hide the navigation bar by setting its isNavigationBarHidden property to true.


The following Swift 5.1 / iOS 13 code sample shows how to implement your UIViewController subclass to make the swipe from top gesture work:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationController?.isNavigationBarHidden = true

        let gestureRecognizer = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(swipeFromTop))
        gestureRecognizer.edges = .top
        view.addGestureRecognizer(gestureRecognizer)
    }

    @objc func swipeFromTop() {
        print("swipe from top")
    }

    override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge {
        .top
    }

    override var prefersStatusBarHidden: Bool {
        true
    }

}

Sources: