1

I've implemented SWRevealViewController for a slide-out menu in my Swift app. One issue with this framework is that when the menu (rearView) is expanded the user can still interact with the frontView. Since my frontView is a full bleed map it's very difficult to close the menu by tapping on the frontView, because instead of recognizing it as a pan/tap to close it just moves the map around.

There is the same questions for Objective-C here. The top answer from @hardluckbaby seems to be the best solution, but it's in Objective-C. I've gotten the first part of the answer working in Swift, I need help with the second part.

In my rearView controller if added these two functions which successfully disable interactions on the frontView when the rearView (menu) is open:

override func viewWillAppear(animated: Bool) {
  self.revealViewController().frontViewController.view.userInteractionEnabled = false  
}

override func viewWillDisappear(animated: Bool) {
  self.revealViewController().frontViewController.view.userInteractionEnabled = true
}

This final part I need help converting to Swift. It's suppose to re-enable the pan/tap gestures for my frontView. In my frontView I'm suppose to place the following in my ViewDidLoad function:

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

How can this last part be written in Swift?

I tried adding it to this function, but it doesn't recognize my taps. Do I need to take it out of this IF statement?

override func viewDidLoad() {
   super.viewDidLoad()

   if self.revealViewController() != nil {
     self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
     self.view.addGestureRecognizer(self.revealViewController().tapGestureRecognizer())
   }
}
Community
  • 1
  • 1
tylerSF
  • 1,479
  • 2
  • 16
  • 25

2 Answers2

4

Found a different solution that still achieves the same result (disable interaction with frontView when rearView/menu is open). It also has an additional benefit of "dimming" the frontView to focus the user on the menu.

There is no code needed in the menuController, I removed the code in viewWillAppear and viewWillDisappear that I referenced in my question.

Below is what I added to my frontView controller. One downside is that this code needs to be included on all controllers that you want to disable interaction on when the menu is open.

Make sure to add SWRevealViewControllerDelegate to where you declare your class.

Full frontViewController code:

// make sure to add SWRevealViewControllerDelegate to the class declaration
class LocationConfirmViewController: UIViewController, SWRevealViewControllerDelegate {    

  @IBOutlet weak var menuBtn: UIBarButtonItem!

  override func viewDidLoad() {
      super.viewDidLoad()

      //menu button control
      if self.revealViewController() != nil {
        menuBtn.target = self.revealViewController()
        menuBtn.action = "revealToggle:"

        //new line to declare delegate
        self.revealViewController().delegate = self
        self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
      }
  }


  // MARK: - Navigation

  //controls the frontView when the menu is opened.
  //creates a mask that dims the view and blocks any interaction except for tap or pan to close the menu.
  func revealController(revealController: SWRevealViewController!, willMoveToPosition position: FrontViewPosition){
      let tagId = 4207868622

      if revealController.frontViewPosition == FrontViewPosition.Right {
          let lock = self.view.viewWithTag(tagId)
          UIView.animateWithDuration(0.25, animations: {
              lock?.alpha = 0
              }, completion: {(finished: Bool) in
                  lock?.removeFromSuperview()
              }
          )
          lock?.removeFromSuperview()
      } else if revealController.frontViewPosition == FrontViewPosition.Left {
          let lock = UIView(frame: self.view.bounds)
          lock.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
          lock.tag = tagId
          lock.alpha = 0
          lock.backgroundColor = UIColor.blackColor()
          lock.addGestureRecognizer(UITapGestureRecognizer(target: self.revealViewController(), action: "revealToggle:"))
          self.view.addSubview(lock)
          UIView.animateWithDuration(0.5, animations: {
              lock.alpha = 0.333
              }
          )
      }
  }
}

Credit to @mixth and his answer here to a similar question. I made some changes and added more of a description on how to exactly implement. Since I'm new to Swift I had trouble understanding his answer. Hopefully this help others.

Community
  • 1
  • 1
tylerSF
  • 1,479
  • 2
  • 16
  • 25
  • You wrote `lock?.removeFromSuperview()` when the frontposition was right, why not remove it after completion of the left view? – Munib Dec 06 '16 at 05:43
  • @tylerSF this method is not calling for me func revealController(revealController: SWRevealViewController!, willMoveToPosition position: FrontViewPosition) in swift 3 – Uma Madhavi Jun 07 '17 at 06:19
  • @UmaMadhavi did you add SWRevealViewControllerDelegate to the class declaration? – tylerSF Jun 08 '17 at 14:03
1

You need to move that code into viewDidAppear because viewDidLoad will only get called the first time, while the other function will be called every time the view shows back up on screen.

pbush25
  • 5,228
  • 2
  • 26
  • 35
  • moving the second part to `viewDidAppear` did not change anything. The frontView is still not clickable. Is my If statement the correct translation of the Obj-C code? – tylerSF Feb 20 '16 at 20:56
  • Yes that's correct. Maybe try setting revealViewController's delegate to self – pbush25 Feb 20 '16 at 20:59
  • hmm. that still didn't work. But I did finally another way to get the view to dim properly. Will post the full answer below. – tylerSF Feb 20 '16 at 21:26
  • @pbush25 . my delegate method is not calling i am not understanding why it happens – Uma Madhavi Jun 07 '17 at 06:22