How do I set up an UIScreenEdgePanGestureRecognizer using Interface Builder?

20,895

Solution 1

I set up a project to test your question and found the same issue you did. Here are the scenarios I set up to test:

  • I did exactly as you did, using Interface Builder, to build the screen edge gesture. The only difference in my code is that I put a line of code in the selector so the debugger would have something to stop on. The debugger failed to halt exactly as you found.

    -(void)handlePan:(id)sender
    {
        NSString *test = @"";
    }
    
  • I then created an additional gesture using the pinch gesture on the same view using Interface Builder and I was able to get the debugger to halt within that selector. So Interface Builder seems to be able to build other gestures correctly.

  • I then created the screen edge gesture manually using the following code and it worked as expected.

In the ViewController.h file I included the UIGestureRecognizerDelegate.

@interface ViewController : UIViewController <UIGestureRecognizerDelegate>
@end

In the ViewController.m file I implemented the gesture manually.

#import "ViewController.h"

@interface ViewController ()

-(void)handlePan:(id)sender;

@end

@implementation ViewController

- (void)viewDidLoad 
{
    [super viewDidLoad];
    UIScreenEdgePanGestureRecognizer *pan = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self
                                                                                              action:@selector(handlePan:)];
    [pan setEdges:UIRectEdgeLeft];
    [pan setDelegate:self];
    [self.view addGestureRecognizer:pan];
}

-(void)handlePan:(id)sender
{
    NSString *test = @"";
}

@end

I ended up with the same conclusion you did - there seems to be something wrong with the Interface Builder's implementation of the UIScreenEdgePanGestureRecognizer.

Solution 2

I have tried it in Xcode 7.0 Beta 4 (7A165t) and it's still a bug. Adding the Screen Edge Pan Gesture Recognizer via Interface Builder doesn't call the referenced IBAction, however adding it programmatically like this works fine:

class ViewController: UIViewController, UIGestureRecognizerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let edgeGestureRecognizer = UIScreenEdgePanGestureRecognizer(target: self, action: "userSwipedFromEdge:")
        edgeGestureRecognizer.edges = UIRectEdge.Left
        edgeGestureRecognizer.delegate = self
        self.view.addGestureRecognizer(edgeGestureRecognizer)
    }

    func userSwipedFromEdge(sender: UIScreenEdgePanGestureRecognizer) {
        if sender.edges == UIRectEdge.Left {
            print("It works!")
        }
    }
}

Hint: Don't forget to add the UIGestureRecognizerDelegate protocol to your class. Otherwise you'll get an error at edgeGestureRecognizer.delegate = self

Solution 3

It can be considered as a bug, but actually, here is something useful:

"After creating a screen edge pan gesture recognizer, assign an appropriate value to the edges property before attaching the gesture recognizer to your view."

https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIScreenEdgePanGestureRecognizer_class/index.html

This requirement only apply to UIScreenEdgePanGestureRecognizer, so I think that's why Xcode make it wrong, it must be implemented as the normal sequence, alloc->init->attach->set value. It will work to all other GestureRecongnizer but not UIScreenEdgePanGestureRecognizer.

Solution 4

Xcode isn’t always a good neighbor. Sorry.

override func viewDidLoad() {
    super.viewDidLoad()

    let panGesture = UIScreenEdgePanGestureRecognizer(target: self, action: "panAction:")
    panGesture.edges = .Left
    view.addGestureRecognizer(panGesture)
}


func panAction(sender: UIScreenEdgePanGestureRecognizer) {
    let translation = sender.translationInView(sender.view!)

    println("Trans:\(translation)")
}

Solution 5

To make sure that multiple gesture recognizers can work together you have to implement the method shouldRecognizeSimultaneouslyWithGestureRecognizer and return true:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

Sorry for the Swift code but you should get the idea.

This method must be implemented even if you are using a single gesture recognizer because the view can have its own (system) recognizers, such as MKMapView.

Share:
20,895
j b
Author by

j b

Music Technology R &amp; D

Updated on July 09, 2022

Comments

  • j b
    j b almost 2 years

    I can't get UIScreenEdgePanGestureRecognizer to work when I create when I add it to my view controller using Interface Builder, so I'm asking here to establish whether I'm doing something wrong or if there is a bug in Xcode.

    Here are the steps to reproduce:

    • Create a new Xcode project using the "Single View Application" template for iOS.
    • Add a UIView to the main view controller by dragging one from the Object Library in Interface Builder
    • Add a UIScreenEdgePanGestureRecognizer to the view by dragging one from the Object Library in Interface Builder
    • Ensure that the gesture recogniser is enabled and that an edge is selected:

    enter image description here

    • Open the assistant editor for the ViewController class and ctrl-drag from the UIScreenEdgePanGestureRecognizer to the ViewController's implementation block to create a new IBAction ` Add a breakpoint in the action's method body to test if the edge pan gesture is being recognized

    The resulting code is as follows:

    Code example

    If I run the application on my device (iPhone 6 running iOS 8.02) the breakpoint does not get hit when I do an edge swipe.

    Is there something I'm missing?

    UPDATE: this was filed as a bug with Apple (rdar://18582306) on 08-Oct-2014 and still isn't resolved in Xcode 6.4 (6E35b)