1

I am trying to implement a view with sliding side menus, such as with PKRevealController in iOS 6.1. A simple demo of this issue with source code on github is here, however you might not need to grab it if you already understand gestureRecognizer delegate implementation.

The problem I see is that two gestures that my users will want to use are going to be mutually confused for each other. The UITableView in the center (main screen) of the application should be able to use the swipe-right gesture to delete, but I still want a swipe that occurs across the top navigation area to result in exposing the side menus.I also intend to show other things than just the Table view, and at runtime I plan to swap out the main view with a different view, whenever a user selects a button on one of the side menus. This is kind of like a "hidden side tray UITabBarController" that I'm going for, but I want the side bars to be revealed only when the main "front view" controller is NOT a UITableView or its subviews.

Right now, using the demo sources that comes with PKRevealController, and adding deletion support to the main view's UITableView, no slide gesture to delete a row is possible. (You have to add one table view method to enable deletion support in the UITable view, which I did add.)

This was asked here, but the answer stated is incomplete, and as seen below, does not work for me and I have no idea why, because it appears that this delegate method is not invoked at any time where I return a YES, and yet it goes ahead anyways and begins a gesture. Update The answer in the previous question is also wrong, as compared to the WIKI/FAQ answer I placed below.

I have only modified the class PKRevealController.m by adding this:

- (BOOL)                             gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {

    UIView *view1 = otherGestureRecognizer.view;
    UIView *view2;
    if (view1) {
         view2 = view1.superview;
    };

    if ([gestureRecognizer.view isKindOfClass:[UITableView class]])
    {
        return NO;
    }
    // Co-operate by not stealing gestures from UITableView.
    if ([view1 isKindOfClass:[UITableView class]]) {
        return NO;
    }else if ([view1 isKindOfClass:[UITableViewCell class]]) {
        return NO;
        // UITableViewCellContentView
    }
    else if (view2 && [view2 isKindOfClass:[UITableViewCell class]]) {
        return NO;
        // UITableViewCellContentView
    }
    else
    {
        return YES;    // NEVER GETS HIT. BREAKPOINT HERE!
    }
}

What confuses me is that at no point does the return YES code above get hit (I have a breakpoint on it) and yet, the Gesture controller is still stealing the gesture.

Note: I have made an evil hack, but I thought that I could prevent this cleanly. Here is my evil hack:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer == self.revealPanGestureRecognizer)
    {
        CGPoint translation = [self.revealPanGestureRecognizer translationInView:self.frontViewContainer];
        BOOL begin = (fabs(translation.x) >= fabs(translation.y));

        // BEGIN EVIL HACK
        if (_topLimitY > 0) {
         CGPoint location = [gestureRecognizer locationInView:gestureRecognizer.view];
         if (location.y>_topLimitY) // _topLimitY = 55 for instance.
            begin = NO;
        }
        // END EVIL HACK.

        return begin;
    }
    else if (gestureRecognizer == self.revealResetTapGestureRecognizer)
    {
        return ([self isLeftViewVisible] || [self isRightViewVisible]);
    } 

    return YES;
}

Right now in my evil hacked demo, I have set the topLimitY property (that I added to PKRevealController's properties) to 55, which allows me to swipe on the nav bar area of the front view, but not on the table view which takes up the rest of the demo.

Note that I plan to have multiple main views, and only want to defeat the gesture recognition on the whole main area if the view is a UITableView or some sub-view thereof. That is why I call my hack above a hack. Because I thought you could tell the gesture recognizer to go away and not bother you, and yet it doesn't work, it doesn't even invoke the shouldRecognize method, it just goes ahead and does the next thing in its list of things to do.

enter image description here

Community
  • 1
  • 1
Warren P
  • 65,725
  • 40
  • 181
  • 316

2 Answers2

4

I should really read the WIKI first shouldn't I?

This is a FAQ, it says so right here:

When instantiating the controller pass this option in your options dictionary:

  NSDictionary *options = @{
      PKRevealControllerRecognizesPanningOnFrontViewKey : @NO
  };

This will disable pan-based reveal for the entire front view. Now, you can use the revealPanGestureRecognizer and add it to any view you desire to be panned on that doesn't interfere with your table view, to enable gesture based reveal. I'd advise (if working with a table based environment with swipe'able cells) you, to add the revealPanGestureRecognizer to your front view controller's navigation bar (which it most likely has):

  [self.navigationController.navigationBar addGestureRecognizer:self.revealController.revealPanGestureRecognizer];

And voilĂ  - panning doesn't interfere with your table view anymore.

more info at: https://github.com/pkluz/PKRevealController/issues/76

Thank you Wiki. If only I had read it all first.

The above completely answers my question and was already there on the wiki. I'm answering my own question because it seems Google always comes to Stackoverflow first, and that might help other confused developers in the future.

Update If the above thing blows up when you try it, it's probably being done too early. Here's a slightly more robust version of the above fix:

// Additional gesture recognition linkups. The underscore variables here
// are implementation-section ivars in my app-delegate,  that I have already 
// checked are valid and initialized, and this is the last thing in my app delegate
// didFinishLaunch... method, before the return YES:

UIGestureRecognizer *rec = _revealController.revealPanGestureRecognizer;
if (rec) {
    [_frontViewNavController.navigationBar addGestureRecognizer:rec];
}
Warren P
  • 65,725
  • 40
  • 181
  • 316
4

Use This :

self.revealController.frontViewController.revealController.recognizesPanningOnFrontView = YES;
Sanoj Kashyap
  • 5,020
  • 4
  • 49
  • 75