14

I need to disable user interaction on front view when rear view is revealed. Found some others asking the same thing but can't really understand where or how to implement the code that I've seen.

Ex: I found this code from link,

- (void)revealController:(SWRevealViewController *)revealController 
      willMoveToPosition:(FrontViewPosition)position {
    if(position == FrontViewPositionLeft) {
        self.view.userInteractionEnabled = YES;
    } else {
        self.view.userInteractionEnabled = NO;
    } 
}

- (void)revealController:(SWRevealViewController *)revealController 
       didMoveToPosition:(FrontViewPosition)position {
    if(position == FrontViewPositionLeft) {
        self.view.userInteractionEnabled = YES;
    } else {
        self.view.userInteractionEnabled = NO;
    } 
}

Also found few other links

I have this code, but not really sure about the correct place to insert this code. I've tried adding it in my front/rear views and also in the SWRevealViewController method with no success

Appreciate if someone can point me in the right direction.

Community
  • 1
  • 1
Mou某
  • 466
  • 2
  • 8
  • 30

15 Answers15

53

I've recently come up with a solution that I wanted to share (sorry if it's 2 months late).

To disable user interaction on the Front View while the Menu is open, I added the following codes on my MenuViewController:

on viewWillAppear:

[self.revealViewController.frontViewController.view setUserInteractionEnabled:NO];

and on viewWillDisappear:

[self.revealViewController.frontViewController.view setUserInteractionEnabled:YES];

This will disable all user interactions on the Front View Controller, which means that the slide / tap gestures to CLOSE the menu will also be DISABLED.

Now, I have created a ParentViewController and made all the view controllers (the menu items) a subclass of it.

on my viewDidLoad, I put the following codes:

SWRevealViewController *revealController = [self revealViewController];
[revealController panGestureRecognizer];
[revealController tapGestureRecognizer];

If you run your app at this point, it would appear that the Tap Gesture works (a tap on the Front View will close the Menu), but NOT the Pan Gesture. I'm not sure why this is so, but in order to enable the slide gesture to CLOSE your menu, add the following code in your MenuViewController:

on viewWillAppear:

[self.revealViewController.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];

To summarize, here's what you need:

On your MenuViewController:

-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    [self.revealViewController.frontViewController.view setUserInteractionEnabled:NO];
    [self.revealViewController.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}

-(void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];

    [self.revealViewController.frontViewController.view setUserInteractionEnabled:YES];
}

And on your menu items' view controller (you can make a ParentViewController for all of them):

-(void)viewDidLoad {
    [super viewDidLoad];

    SWRevealViewController *revealController = [self revealViewController];
    [revealController panGestureRecognizer];
    [revealController tapGestureRecognizer];
}

Hope this helps!

aj_f
  • 932
  • 7
  • 12
  • it more than helps - super simple & super super – Mou某 Jun 01 '14 at 08:27
  • You can use this fork too: http://nsrover.wordpress.com/2014/08/06/swrevealviewcontroller-disabling-user-interaction-when-toggled-to-rearview/ – NSRover Aug 06 '14 at 10:38
  • The only snag with this is that a pan gesture anywhere on the screen, including over that back menu screen will move the frontViewController. Anyone got a way of limiting the swipeable area? – Peter Johnson Jun 10 '15 at 20:57
  • very clever.. Thanks – John Paul Manoza Jan 24 '16 at 11:23
  • For the last part of the viewDiDLoad portion how would you write it in swift? `SWRevealViewController *revealController = [self revealViewController]; [revealController panGestureRecognizer]; [revealController tapGestureRecognizer];` I was able to get the first part working in Swift to disable gestures, just need to get them back :) – tylerSF Feb 20 '16 at 19:33
  • This answer helped me solve another question! Thanks! (how to darken front view when rear is revealed). – Munib Dec 22 '16 at 03:21
13

I have used another approach to achieve the same outcome not sure if it helps.

Assign SWRevealViewControllerDelegate to AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    SWRevealViewController* reveal = (SWRevealViewController*)self.window.rootViewController;
    reveal.delegate = self;

    // other bootstrapping code
}

and then in the delegate method -(void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position as below:

-(void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position
{
    if(position == FrontViewPositionLeft){
        [revealController.frontViewController.view setUserInteractionEnabled:YES];
        [revealController.frontViewController.revealViewController tapGestureRecognizer];
    }else{
        [revealController.frontViewController.view setUserInteractionEnabled:NO];
    }
}

UPDATED: added this line [revealController.frontViewController.revealViewController tapGestureRecognizer] to close the revealed controller when tap on frontviewcontroller

xun
  • 386
  • 3
  • 10
6

Swift version to @hardluckbaby answer:

In MenuViewController(Rear view controller):

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    self.revealViewController().frontViewController.view.userInteractionEnabled = false
    self.revealViewController().view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)

    self.revealViewController().frontViewController.view.userInteractionEnabled = true
}

In FrontViewController(You can make a ParentViewController for all of your front view controllers as @hardluckbaby said):

override func viewDidLoad() {
    super.viewDidLoad()

    if let revealController = self.revealViewController() {
        revealController.panGestureRecognizer()
        revealController.tapGestureRecognizer()
    }
}
Ashok
  • 5,085
  • 5
  • 45
  • 74
3

As John Explained: Although these solutions do work, I don't think any of them address the original question, which is actually quite simple:

There are 2 steps involved:

  1. Add the following methods to your FrontViewController.m:

    • (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position { if(position == FrontViewPositionLeft) { self.view.userInteractionEnabled = YES; } else { self.view.userInteractionEnabled = NO; } }

    • (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position { if(position == FrontViewPositionLeft) { self.view.userInteractionEnabled = YES; } else { self.view.userInteractionEnabled = NO; } }

  2. Make your front view controller be a delegate of SWRevealViewController in the FrontViewController.h file:

(e.g. @interface HomeViewController : UIViewController ) where my FrontViewController was named HomeViewController

and also in the FrontViewController.m file with the following on ViewDidLoad:

self.revealViewController.delegate = self; Problem solved! Much easier than creating parent classes, etc.

This will help you solve the user interactions for the FrontView controller lovely I would just add the following change taken from Xun's response also above and you will solve both the user interactions and the hide menu when user taps FrontViewController.

- (void)revealController:(SWRevealViewController *)revealController 
      willMoveToPosition:(FrontViewPosition)position {
    if(position == FrontViewPositionLeft) {
        self.view.userInteractionEnabled = YES;
    } else {
        self.view.userInteractionEnabled = NO;
    } 
}

- (void)revealController:(SWRevealViewController *)revealController 
       didMoveToPosition:(FrontViewPosition)position {
    if(position == FrontViewPositionLeft) {
        self.view.userInteractionEnabled = YES;
    } else {
        self.view.userInteractionEnabled = NO;
      //Hides the menu when user taps FrontViewController
       [revealController.frontViewController.revealViewController tapGestureRecognizer];
    } 
}
peterh
  • 9,698
  • 15
  • 68
  • 87
2

Swift 3.0 simple and fast method.

Frontviewcontoller code here...

override func viewDidLoad() {
    super.viewDidLoad()
     if self.revealViewController() != nil {
        let rewel:SWRevealViewController  = revealViewController()
        rewel.panGestureRecognizer()
        rewel.tapGestureRecognizer() 
    }
}

SideDrowerviewcontoller code here...

override func viewWillAppear(_ animated: Bool) {
  let rewel = self.revealViewController()
      rewel?.frontViewController.view.isUserInteractionEnabled = false
    rewel?.frontViewController.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}

override func viewWillDisappear(_ animated: Bool) {
    let rewel = self.revealViewController()
        rewel?.frontViewController.view.isUserInteractionEnabled = true
}
Raksha Saini
  • 585
  • 12
  • 27
1

Add a subview to front view when rear view is open.

Mayank Jain
  • 5,476
  • 7
  • 29
  • 64
  • can I get a little sample code? I tried adding `for(UIView *view in self.revealViewController){....}` in my ViewDidLoad but I think I'm doing something wrong – Mou某 Mar 24 '14 at 09:08
1

In viewWillAppear method of your menu items controller, Just create an overlay button on the front view and set action to revealToggle: of revealViewController

-(void)viewWillAppear:(BOOL)animated 
{
    [super viewWillAppear:animated];
    overlayView = [UIButton buttonWithType:UIButtonTypeCustom];
    overlayView.frame = self.revealViewController.frontViewController.view.bounds;
    overlayView.backgroundColor = [UIColor colorWithWhite:0.5 alpha:0.8];
    overlayView.tag = 999;
    [overlayView addTarget:self.revealViewController action:@selector(revealToggle:) forControlEvents:UIControlEventTouchUpInside];
    [overlayView addTarget:self.revealViewController action:@selector(revealToggle:) forControlEvents:UIControlEventTouchDragOutside];
    [self.revealViewController.frontViewController.view addSubview:overlayView];
}

In revealTogglle method remove the overlay button if any:

- (void)revealToggleAnimated:(BOOL)animated
{
    UIButton *overlayView = (UIButton*)[self.view viewWithTag:999];
    if (overlayView) {
        [overlayView removeFromSuperview];
        overlayView = nil;
    }
    // rest of the code...
}
Amita_S
  • 61
  • 7
1

Although these solutions do work, I don't think any of them address the original question, which is actually quite simple:

There are 2 steps involved:

1) Add the following methods to your FrontViewController.m:

- (void)revealController:(SWRevealViewController *)revealController 
      willMoveToPosition:(FrontViewPosition)position {
    if(position == FrontViewPositionLeft) {
        self.view.userInteractionEnabled = YES;
    } else {
        self.view.userInteractionEnabled = NO;
    } 
}

- (void)revealController:(SWRevealViewController *)revealController 
       didMoveToPosition:(FrontViewPosition)position {
    if(position == FrontViewPositionLeft) {
        self.view.userInteractionEnabled = YES;
    } else {
        self.view.userInteractionEnabled = NO;
    } 
}

2) Make your front view controller be a delegate of SWRevealViewController in the FrontViewController.h file:

(e.g. @interface HomeViewController : UIViewController <SWRevealViewControllerDelegate>)

where my FrontViewController was named HomeViewController

and also in the FrontViewController.m file with the following on ViewDidLoad:

self.revealViewController.delegate = self;

Problem solved! Much easier than creating parent classes, etc.

John
  • 1,437
  • 3
  • 14
  • 23
1

Another way is to have an overlay view when the rear view is revealed. You can use this updated library https://github.com/NSRover/SWRevealViewController and make sure you include shouldUseFrontViewOverlay = true when the rear view is revealed.

thedansaps
  • 501
  • 3
  • 8
  • 17
1
class SideMenuViewController: UITableViewController {

  override func viewDidLoad() {
    super.viewDidLoad()
    self.revealViewController().delegate = self
  }

}

extension SideMenuViewController: SWRevealViewControllerDelegate {

  func revealController(revealController: SWRevealViewController!, willMoveToPosition position: FrontViewPosition) {
    if position == .Left {
      revealController.frontViewController.view.userInteractionEnabled = true
    }

    if position == .Right {
      revealController.frontViewController.view.userInteractionEnabled = false
    }
  }

}
Bryan Lin
  • 101
  • 1
  • 2
0
On MenuTableViewController/ Rear VC, add SWRevealViewControllerDelegate.

    override func viewDidLoad() {
        super.viewDidLoad()
        self.revealViewController().delegate = self

        if self.revealViewController() != nil {
            self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
        }
    }

Add this delegate method.

func revealController(revealController: SWRevealViewController!, didMoveToPosition position: FrontViewPosition) {
        if(position.rawValue == 4)
        {
            //move to rear
            self.revealViewController().frontViewController.view.userInteractionEnabled =  false
        }
        else if (position.rawValue == 3)
        {
            //move to front - dashboard VC
            self.revealViewController().frontViewController.view.userInteractionEnabled =  true
        }
    }
    func revealController(revealController: SWRevealViewController!, willMoveToPosition position: FrontViewPosition) {

//will perform the same function as the above delegate method.
    }
A.G
  • 13,048
  • 84
  • 61
0

Consider following solution, works perfect

private let DimmingViewTag = 10001

extension UIViewController: SWRevealViewControllerDelegate {    

    func removeInteractionFromFrontViewController() {

        revealViewController().delegate = self

        view.addGestureRecognizer(revealViewController().panGestureRecognizer())
    }

    //MARK: - SWRevealViewControllerDelegate

    public func revealController(revealController: SWRevealViewController!, didMoveToPosition position: FrontViewPosition) {

        if case .Right = position {

            let dimmingView = UIView(frame: view.frame)
            dimmingView.tag = DimmingViewTag

            view.addSubview(dimmingView)
            view.bringSubviewToFront(dimmingView)

        } else {
            view.viewWithTag(DimmingViewTag)?.removeFromSuperview()
        }
    }
}

Simple usage in UIViewController:

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

    removeInteractionFromFrontViewController()
}
Bartłomiej Semańczyk
  • 52,820
  • 43
  • 206
  • 318
0

Addition to hardluckbaby answer.

If you run your app at this point, it would appear that the Tap Gesture works (a tap on the Front View will close the Menu), but NOT the Pan Gesture. I'm not sure why this is so, but in order to enable the slide gesture to CLOSE your menu, add the following code in your MenuViewController:

on viewWillAppear:

[self.revealViewController.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];

It adds some undesired behavior, e.g. pan gesture will close rear view when starts on it.

Default pan gesture may not work if you add it to your own view somewhere, something like on viewDidLoad of your front view controller:

[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];

Remove such lines and this should works as expected, for pan and tap gestures

SWRevealViewController *revealController = [self revealViewController];
[revealController panGestureRecognizer];
[revealController tapGestureRecognizer];
art-of-dreams
  • 229
  • 3
  • 11
0

I was using the viewWillAppear and viewWillDisappear functions but as I have subviews for almost every item in the side menu I had. My issue was that I had a input field active (keyboard displaying) and accessed the side menu. In the root menu the keyboard hid but after I entered a submenu keyboard showed up again. To solve this I changed the approach to enable and disable the interaction in revealController like this:

- (void)revealController:(SWRevealViewController *)revealController 
        didMoveToPosition:(FrontViewPosition)position {
    if (position == FrontViewPositionRight) {
        [self.revealViewController.frontViewController.view setUserInteractionEnabled:NO];
    } else if (position == FrontViewPositionLeft) {
        [self.revealViewController.frontViewController.view setUserInteractionEnabled:YES];
    }
}
mxmlc
  • 449
  • 4
  • 19
0

Firstly just set your delegate : self.revealViewController.delegate = self; and the delegate method are given below :

- (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position
{
    static NSInteger tagLockView = 123456789;
    if (revealController.frontViewPosition == FrontViewPositionRight)
    {
        UIView *lockView = [self.view viewWithTag:tagLockView];

        [UIView animateWithDuration:0.3 animations:^{
            lockView.alpha = 0;
        } completion:^(BOOL finished) {
            [lockView removeFromSuperview];
        }];
    }
    else if (revealController.frontViewPosition == FrontViewPositionLeft)
    {
        UIView *lockView = [[UIView alloc] initWithFrame:self.view.bounds];
        lockView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        lockView.tag = tagLockView;
        lockView.backgroundColor = [UIColor blackColor];
        lockView.alpha = 0;
        [lockView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self.revealViewController action:@selector(revealToggle:)]];
        [self.view addSubview:lockView];
        [UIView animateWithDuration:0.3 animations:^{
            lockView.alpha = 0.5;
        }];
    }

}
Priti Kanauziya
  • 165
  • 2
  • 11