I have in my Swift 3 application a homeViewController containing a UITableView. When a cell of the table is clicked, then I display a detailViewController. I display it as a child using the addChildViewController(vc). I want to implement the back gesture in order to return to the homeViewController. I want to have the same result as the back mode in the default Mail application of the devices (the back mode to return to the mail's home when I was in the inbox for example). In other words, the gesture allows the user to drag the view from left to right then continuing the left to right drag until the home view is showed, or drag the view from right to left in order to keep the detail view in the whole screen. I tried to do that using the UIPanGestureRecognizer but my view goes left and right and sometimes its show the home view from the right side. So in brief, the result that I want is the same as the back gesture functionality of the Mail application.
This is my code:
var rightSwipe: UIPanGestureRecognizer = UIPanGestureRecognizer()
self.rightSwipe = UIPanGestureRecognizer(target: self, action: #selector(self.handleSwipes(_:)))
self.view.addGestureRecognizer(rightSwipe)
func handleSwipes(_ sender: UIPanGestureRecognizer){
if self.rightSwipe.state == .began || self.rightSwipe.state == .changed {
let translation = rightSwipe.translation(in: self.view)
// note: 'view' is optional and need to be unwrapped
//print("translation is : \(translation)")
if(translation.x > 0 && translation.y == 0.0){
self.rightSwipe.view!.center = CGPoint(x: self.rightSwipe.view!.center.x + translation.x, y: self.rightSwipe.view!.center.y + translation.y)
rightSwipe.setTranslation(CGPoint.zero, in: self.view)
}
}
}
To use NavigationController in your storyboard embeded your HomeViewController with UINavigationController. To embed navigationController select your HomeViewController, in menu choose Editor > Embed In > Navigation Controller.
Now in didSelectRowAt indexPath push the detailViewController.
self.navigationController?.pushViewController(detailVC, animated: true)
If still gesture is not work then in HomeViewController's viewDidLoad set this one.
self.navigationController?.interactivePopGestureRecognizer.isEnabled = true
Related
I have a ViewController (LandingViewController) and one drawerViewController.
I am using SWRevealViewController and I added a gesture to Landing view but when it will open the DrawerViewController then it is covering status bar only once. I don't know why this is happening, But it is hiding once and after that working fine.
I am not using NavigationBar and I have a map view in my LandingViewController.
I have drawer button in my LandingViewController.
If I will open or reveal the view by button it's working fine. But if I will open it by view it is hiding status bar.
Here below is my code :-
btnDrawerMenu.addTarget(self.revealViewController(), action: #selector(SWRevealViewController.revealToggle(_:)), for: UIControlEvents.touchUpInside).
//Reveal View Drawer menu
fileprivate func createReveal() {
if self.revealViewController() != nil {
self.revealViewController().rearViewRevealWidth = self.view.frame.width - 20
self.revealViewController().rearViewRevealOverdraw = 0.0
self.revealViewController().bounceBackOnOverdraw = false
self.revealViewController().bounceBackOnLeftOverdraw = false
self.revealViewController().toggleAnimationType = .easeOut
}
}
I am having trouble my UIPageViewController. What I ve done sofar:
1. On pageViewController you can swipe left, right in order to change VC
2. added lateral menu. When adding lateral menu, I created pangesture recognizer and added it to pageContentVC (so I can drag pageContentVC in order to close sidebar menu)
var menuViewController: UIViewController! {
didSet {
self.exitPanGesture = UIPanGestureRecognizer()
self.exitPanGesture.addTarget(self, action:"handleOffstagePan:")
// self.exitPanGesture.view?.userInteractionEnabled = false
self.sourceViewController.view.addGestureRecognizer(self.exitPanGesture)
}
}
Here I am setting pageContentVC to sourceVC of transitionManager:
func resetToMainPage(index: Int!) {
/* Getting the page View controller */
mainPageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("MainPageViewController") as UIPageViewController
self.mainPageViewController.dataSource = self
self.mainPageViewController.delegate = self
let pageContentViewController = self.viewControllerAtIndex(index)
self.transtionManger.sourceViewController = pageContentViewController // adding swipe to the pageContentViewControlle in order to close menu
self.mainPageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
self.mainPageViewController.view.frame = CGRectMake(0, 102, self.view.frame.width, self.view.frame.height)
self.addChildViewController(mainPageViewController)
self.view.addSubview(mainPageViewController.view)
self.mainPageViewController.didMoveToParentViewController(self)
}
After closing menu I disabled pangesture recognizer.
` var presentingP:Bool!{
didSet{
if presentingP == true {
// enable the gesture recognizer only when the view of menucontroller is presented
self.exitPanGesture.view?.userInteractionEnabled = true
}else{
// disable gesture recognizer when menu is not presented
self.exitPanGesture.view?.userInteractionEnabled = false
isMenuVisible = false
}
}
}
` Sofar, I can swipe left, and right in order to change VC.
The problem is that I can't scroll tableView on my VC. After I disabled pageContentVC gesture, everything become disable except swiping right and left (to change VC). Question: How to keep two gestureRecognizers in one view and switch between them?
You can use the enabled property of UIGestureRecognizer to disable the one you don't want to use and enable the other one.
UIGestureRecognizer documentation
I am making app like in Euro Sport. My rootviewController is pageViewController which has 3 VCs. Swiping left and right you can change the VC. Next, I added sidebarmenu. I want to add gesture recognizer to the whole rootViewController. This is how I am adding gesture:
self.exitPanGesture = UIPanGestureRecognizer()
self.exitPanGesture.addTarget(self, action:"handleOffstagePan:")
self.sourceViewController.view.addGestureRecognizer(self.exitPanGesture)
self.sourceViewController.navigationController?.view.addGestureRecognizer(self.exitPanGesture)
When I drag rootviewController tapping on navigation bar it works. But the other parts like segmentcontrol, and pageContent doesnt work.
I am setting sourceViewController here:
func resetToMainPage(index: Int!) {
/* Getting the page View controller */
mainPageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("MainPageViewController") as UIPageViewController
self.mainPageViewController.dataSource = self
self.mainPageViewController.delegate = self
pageContentViewController = self.viewControllerAtIndex(index)
// self.transtionManger.sourceViewController = pageContentViewController // adding swipe to the pageContentViewControlle in order to close menu
self.transtionManger.sourceViewController = mainPageViewController
self.mainPageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
self.mainPageViewController.view.frame = CGRectMake(0, 102, self.view.frame.width, self.view.frame.height)
self.addChildViewController(mainPageViewController)
self.view.addSubview(mainPageViewController.view)
self.mainPageViewController.didMoveToParentViewController(self)
}
So, My question is how to add gesture recognizer to the whole rootViewController, including navbar, segmentcontrol, pageviewcontrol?
A gesture recognizer can only be attached to one view. So the lines below mean that only navigationController?.view is getting the gesture added.
self.sourceViewController.view.addGestureRecognizer(self.exitPanGesture)
self.sourceViewController.navigationController?.view.addGestureRecognizer(self.exitPanGesture)
You can just duplicate the gesture recognizer for each view you want to have it on and then add them all that way.
self.exitPanGesture1 = UIPanGestureRecognizer()
self.exitPanGesture1.addTarget(self, action:"handleOffstagePan:")
self.sourceViewController.view.addGestureRecognizer(self.exitPanGesture1)
self.exitPanGesture2 = UIPanGestureRecognizer()
self.exitPanGesture2.addTarget(self, action:"handleOffstagePan:")
self.sourceViewController.navigationController?.view.addGestureRecognizer(self.exitPanGesture2)
guys, I solved my problem but I got another one. In my case , I created exitGestureRecognizer. I wanted to add this to whole viewcontroller views. So, here is my code:
for singleView in self.sourceViewController.view.subviews {
singleView.addGestureRecognizer(exitPanGesture)
singleView.navigationController??.view.addGestureRecognizer(exitPanGesture)
}
For some reason, recognizer on navBar.view doesnt work. If I write code in this way:
for singleView in self.sourceViewController.view.subviews {
singleView.addGestureRecognizer(exitPanGesture)
singleView.navigationController??.view.addGestureRecognizer(exitPanGesture)
}
self.sourceViewController.navigationController?.view.addGestureRecognizer(self.exitPanGesture)
Only nav bar gestures work and subview gestures dont work. If I change the order of this code. Nav bar gestures dont work but subviews gestures work. How can I add gestures to both views?
I'm trying to use MMDrawerController in my application, but I can't get the side drawer to close with gestures on the center view. I've used MMDrawerController somewhere else in my app with great success, but can't figure out why its not working in this case.
The top-level View Controller is a UINavigationController, whose default view controller is the MasterViewController (source below). This class extends MMDrawerController and configures the view for what I want (center and right, close gestures, max width). The center view has a button that opens the drawer. Once the drawer is open I can't close it with gestures on the center view. I added a button to the drawer and it can close the drawer programmatically, but I need to be able to tab/pan on the center view.
class MasterViewController: MMDrawerController {
override func viewDidLoad() {
let centerView = storyboard!.instantiateViewControllerWithIdentifier("CenterControllerName") as? CenterControllerType
super.setCenterViewController(centerView, withCloseAnimation: false, completion: nil)
let drawer = storyboard!.instantiateViewControllerWithIdentifier("Drawer") as? DrawerType
super.rightDrawerViewController = drawer
super.setMaximumRightDrawerWidth(200, animated: true, completion: nil)
super.closeDrawerGestureModeMask = MMCloseDrawerGestureMode.PanningCenterView | MMCloseDrawerGestureMode.TapCenterView
}
}
The function to open the drawer:
#IBAction func drawerButtonPressed(sender: AnyObject) {
drawer?.openDrawerSide(MMDrawerSide.Right, animated: true, completion: nil)
}
I was able to work around this by placing a ContainerView as the only object in my view and then configuring the MMDrawerContainer from my ViewController. It doesn't seem like the right answer but everything looks and functions right from the user's perspective.
Ok so I run into the same issue, and I am almost sure that it comes from this:
Ok, the VC1 (with the star) is our application Home, the VC2 is the left drawer, and the VC3 is the DrawerController.
During a long time I tried to put gesture functions in the VC1 and VC2, but only opening in the VC1, and closing in the VC2 would work.
The functions I used in VC1:
let rightSwipe = UISwipeGestureRecognizer(target: self, action: Selector("showDrawer:"))
rightSwipe.direction = .Right
view.addGestureRecognizer(rightSwipe)
...
func showDrawer(sender: UISwipeGestureRecognizer) {
if let m = mmdc {
if !m.isLeftDrawerOpen() {
m.toggleDrawerSide(MMDrawerSide.Left, animated: true, completion: nil)
}
}
}
And the same one in VC2 but with the LeftSwipe and closeDrawer.
The solution is tu put both of these functions and gestures recognizer in the VC3 (DrawerController).
The problem is coming from the fact that your gestures are defined for a given VC, but when you open the drawer, it changes the current VC by a new one, and the previous VC is just displayed but can't be interactif with. By putting things in the parentVC of VC1/VC2 it solves the problem.
I have a menu controller that when it pops up has a collection view. The way it works is that when the user taps outside the collection view it should make the menu dismiss. The menu dismisses when you tap outside the collection view, but it also dismisses when you tap inside the collection view. I can't seem to get the gesture recognizer to only dismiss when it is not inside the collection view. I have looked around on here and google and I haven't found any solution yet that works. Here is the code for the function that handles the tap:
#IBAction func handleTap(sender: MenuTapGestureRecognizer)
{
if (sender.state == .Ended && sender.view == menuCollectionView)
{
NSLog("menuCollectionView")
}
else if (sender.state == .Ended && sender.view == mainView)
{
self.dismissViewControllerAnimated(true, completion: nil)
}
}
mainView is a reference that is connected to the top most view and menuCollectionView is the reference to the UICollectionView.
I suspect you have only attached the gesture recognizer to your mainView. This is fine, but you will want to use sender.locationInView(menuCollectionView) and check to see if the point is within the bounds of your collection view. This is done with the following:
if (CGRectContainsPoint(menuCollectionView.bounds, sender.locationInView(menuCollectionView))) {
// do stuff.
}