UINavigation Swipe Back Gesture use with UIViewController? - ios

In my application I am using the standard UIViewController structure around my app. However I have views which I transition to using a UIStoryboardSegue push. In that UIViewController I am doing this in the viewDidLoad:
self.navigationController.interactivePopGestureRecognizer.delegate = self;
Then I have this delegate method as well to enable the swipe back gesture:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
The problem is, in my original view I presented from, I present a custom menu programmatically in the viewWillAppear using a typical approach like this:
[self.view addSubview:menu];
This works fine if I were to go back to my main menu using
[[self navigationController] popViewControllerAnimated:YES];
However, if I use the swipe back gesture, the view never presents even though the viewWillAppear clearly is called. Is my UINavigationController the issue for this or is something else going on here that I simply do not see?

Related

Having trouble with swipe gesture

I'm having a weird reaction in 1 of my view when swipe to back.
It did not go back to my previous page but other pages does not have this issue. Also, it perform the previous page viewWillAppear code after the swipe.
I did not set any custom back buttons for the views but it is having different effect.
--Edit--
In my previous page that call the affecting page
ViewControllerA *view = [[ViewControllerA alloc] initWithNibName:#"ViewControllerA" bundle:nil];
[self.navigationController pushViewController:view animated:YES];
In my affecting page I only declare viewDidLoad function.
All my navigation for other classes is using the above calling.
By normal clicking the back action at the navigation bar, it will go back to the previous page normally.
--Edit 2--
My current setup is ViewA > ViewB > ViewC where ViewC is where the bug is happening.
At ViewB when I swipe at the edge, it can go back to ViewA.
At ViewC when I swipe at the edge, viewWillAppear in ViewB called but ViewB is not shown.
Tried putting #kaushal answer
if ([self respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationController.interactivePopGestureRecognizer.delegate; //check UIGestureRecognizerDelegate delegate set properly.
}
in both ViewB and ViewC but it did not trigger.
--Edit 3--
I tested my other features flow and it seems that some have this same problem upon entering the third view and some is on the forth view.
In ViewDidAppear: use this code :
if ([self respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationController.interactivePopGestureRecognizer.delegate; //check UIGestureRecognizerDelegate delegate set properly.
}
And check UIGestureRecognizerDelegate is not nil.

UIControllerView Back swipe stops working when setting navigationController.interactivePopGestureRecognizer.delegate = self;

As title says. I had one controller where I was setting interactivePopGestureRecognizer.delegate to handle logic when to allow back swipe gesture and when not. It worked. But now I noticed that once I setup the delegate, the back swipe stops working. It really causes that one line of code. But why?
Yes, the controller where I used to handle the backswipe logic had everything needed (UIGestureRecognizerDelegate protocol, gestureRecognizerShouldBegin delegate method with return YES), but as I say, I discovered in another controller that by just calling the one line of the following code, back swipe doesn't work anymore. (Yes this another controller conforms to UIGestureRecognizerDelegate protocol)
self.navigationController.interactivePopGestureRecognizer.delegate = self;
It doesn't help if I add also:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return YES;
}
or
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
I wonder what is causing this? If I don't call that one line of code, back swipe works! And it even worked in the another controller where I handled the logic as I said.
Edit: I was setting the delegate from viewDidLoad. I tried also from viewDidAppear, but nothing.
The issue is because you are setting multiple ViewController as the delegate. Once you set any ViewController as the UIGestureRecognizerDelegate delegate, that ViewController is responsible for handling the gesture and previously set any delegate will be invalid
To fix the issue you can set the delegate again when view appears in viewWillAppear
self.navigationController.interactivePopGestureRecognizer.delegate = self;
For some reason, if I add the following code to controller, back swipe again works. Maybe it is because i have scrollview in the controller view, but it was working before even without the following code and then it stopped. Strange. (May be i didnt have tableview on the controller where it worked, i dont remember, but i was trying it even with hidden table when it stopped working)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
As said here.

How to prevent UIPopoverPresentationController from being dismissed when clicking outside popover?

In my universal iOS 8 app, I am presenting a popover using using UIPopoverPresentationController as seen below from prepareForSegue:
FavoriteNameViewController *nameVC = segue.destinationViewController;
UIPopoverPresentationController *popPC = nameVC.popoverPresentationController;
popPC.delegate = self;
And with this delegate method.
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone;
}
In this particular case, I'm presenting a view controller that looks like an alert, but isn't.
Now my issue is that the user can click outside of this popover and it gets dismissed. There's no real problem with that except that's not how alerts work and I would like this to emulate an alert.
I see that UIPopoverControllerDelegate had a method called popoverControllerShouldDismissPopover:, but UIPopoverPresentationControllerDelegate doesn't have that method, and I believe I need to use the latter.
You need to set the popover controller's passthroughViews to nil and the view controller's modalInPopover to YES.
Try the following in your view
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
return YES;
}

iOS interactivePopGestureRecognizer enables itself after ViewController is pushed

I have a subclass of UINavigationController that has maximum of 4 ViewControllers in the stack. Lets call them firstVC ... fourthVC. My NavController can perform custom transitions between VCs and ios7/8 back gesture is supposed to be disabled and enabled depending on which VC is currently at the top of the stack. I've set my root VC (firstVC) as a NavController's delegate and trying to enable/disable back gesture in the delegate's method
-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if ([viewController respondsToSelector:#selector(needsBackGestureEnabled)]) {
[self.navigationController.interactivePopGestureRecognizer setEnabled:YES];
NSLog(#"Back gesture enabled");
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
} else {
if ([navigationController.interactivePopGestureRecognizer isEnabled]) {
[self.navigationController.interactivePopGestureRecognizer setEnabled:NO];
NSLog(#"Back gesture disabled");
self.navigationController.interactivePopGestureRecognizer.delegate = nil;
}
}
}
It works like a charm except one glitch. I feel like a short scheme might explain situation better:
FirstVC -[CustomTran]-> SecondVC -[push]-> ThirdVC -[push]-> FourthVC
FourthVC is the only one that have -needsBackGestureEnabled selector, but after transition from second to third back gesture gets enabled by itself. Even though the back button is susbtituted with the CustomBarButtonItem. I feel like performing default -pushViewController animation makes back gesture enabled somehow. I tried to ecplicitly disable it in my NavController subclass in -pushViewController but it didn't change a thing. Any idea why this is happening and how to fix this?

UINavigationBar: intercept back button and back swipe gesture

I have a UINavigationBar that intercepts the back button tap that alerts the user if there are unsave changes. This is based on the solution presented in UINavigationController and UINavigationBarDelegate.ShouldPopItem() with MonoTouch using the UINavigationBarDelegate protocol and implementing - (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;
Now, iOS7 has introduced the swipe-to-go-back gesture, and I'd like to intercept that as well, but can't get it to work with the solutions I've found so far, namely using [self.interactivePopGestureRecognizer addTarget:self action:#selector(handlePopGesture:)]; and
- (void)handlePopGesture:(UIGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateEnded) {
[self popViewControllerAnimated:NO];
}
}
While this does pop the views, it leaves the navigation bar buttons in place, so I'm ending up with a back button that leads nowhere, as well as all other navigation button I've added to the nav bar. Any tips?
To intercept the back swipe gesture you can set self as the delegate of the gesture (<UIGestureRecognizerDelegate>) and then return YES or NO from gestureRecognizerShouldBegin based on unsaved changes:
// in viewDidLoad
self.navigationController.interactivePopGestureRecognizer.delegate = self;
// ...
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]]) {
if (self.dirty) {
// ... alert
return NO;
} else
return YES;
} else
return YES;
}
In the alert you can ask to the user if she want to go back anyway and, in that case, pop the controller in alertView clickedButtonAtIndex:
Hope this is of some help.

Resources