I have custom back buttons all over my app and it looks like navigation controller does not like it.
So, I want the iOS7 swipe-to-go-back gesture to work along with my custom back buttons. Searched and tried different ways but none seems to be promising. The closest I could get is with http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/.
However, Now when I keep pushing and popping the navigation stack, after sometime the rootViewController in the stack stops responding to any touch.
Any suggestions?
Subclassing UINavigationController, like keighl is suggesting, is the right approach imo. But he's missing a check for the root view controller to avoid freezing when the gesture is executed on the root view.
Here's a modified version with the additional check:
CBNavigationController.h:
#import <UIKit/UIKit.h>
@interface CBNavigationController : UINavigationController <UIGestureRecognizerDelegate, UINavigationControllerDelegate>
@end
CBNavigationController.m:
#import "CBNavigationController.h"
@interface CBNavigationController ()
@end
@implementation CBNavigationController
- (void)viewDidLoad
{
NSLog(@"%s",__FUNCTION__);
__weak CBNavigationController *weakSelf = self;
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
{
self.interactivePopGestureRecognizer.delegate = weakSelf;
self.delegate = weakSelf;
}
}
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
NSLog(@"%s",__FUNCTION__);
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
self.interactivePopGestureRecognizer.enabled = NO;
[super pushViewController:viewController animated:animated];
}
#pragma mark UINavigationControllerDelegate
- (void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animate
{
NSLog(@"%s",__FUNCTION__);
// Enable the gesture again once the new controller is shown AND is not the root view controller
if (viewController == self.viewControllers.firstObject)
{
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
self.interactivePopGestureRecognizer.enabled = NO;
}
else
{
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
self.interactivePopGestureRecognizer.enabled = YES;
}
}
@end
objective-c
I've got the same problem, here is my solution:
In your custom NavigationController, like MYNavigationController
, cause you set the gesture delegate to the navigationController, you can add the delegate method there :
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if (self.viewControllers.count>1) {
return YES;
}
return NO;
}
then it will stop the poping action when it's in the root viewController and avoiding the freezing behavior.
Even I had the same problem, I have fix it by modifying code provide in the link which you are referring . Now My screens freezes very rarely still finding for permanent fix.
@implementation PPNavigationController
-(void)viewDidLoad
{
//[super viewDidLoad];
// Do any additional setup after loading the view.
__weak PPNavigationController *weakSelf = self;
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
{
self.interactivePopGestureRecognizer.delegate = weakSelf;
self.delegate = weakSelf;
}
}
-(void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animate
{
// Enable the gesture again once the new controller is shown
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
self.interactivePopGestureRecognizer.delegate = viewController;
}
Don't use this method
//-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
//}
Here is my answer to a similar question asked here
You can use a little trick to get the native gesture working.
Create a subclass of UINavigationItem
, then override leftBarButtonItems
method:
- (NSArray*)leftBarButtonItems
{
return nil;
}
Now use this class for the item that has custom left UIBarButtonItem
. The gesture works! This is because UINavigationController
thinks there are no left items and enables the gesture. You are still able to access your custom item through the leftBarButtonItem
property.
Here's a simple Swift subclass of UINavigationController
you can use that I adapted from @weak's answer. There shouldn't be a need to implement UIGestureRecognizerDelegate
as the nav delegate's navigationController(_:didShow:animated:)
handles the work of enabling and disabling the pop gesture.
Using this subclass in your storyboard or code is easier than doing a one-off disabling in your other controllers that are embedded in nav controllers.
import UIKit
@objc class LWNavigationController : UINavigationController,
UINavigationControllerDelegate {
override func viewDidLoad() {
self.delegate = self
}
override func pushViewController(_ viewController: UIViewController,
animated: Bool) {
// Disable this gesture while animating a push.
self.interactivePopGestureRecognizer?.isEnabled = false
super.pushViewController(viewController, animated: animated)
debugPrint("------\(#function) \(viewController)------")
}
// MARK: - UINavigationControllerDelegate
func navigationController(_ navigationController: UINavigationController,
didShow viewController: UIViewController,
animated: Bool) {
if (viewController == self.viewControllers.first) {
// Keep the gesture disabled if we're at the root to avoid back swipes
// from corrupting the navigation stack.
self.interactivePopGestureRecognizer?.isEnabled = false
} else {
self.interactivePopGestureRecognizer?.isEnabled = true
}
debugPrint("------\(#function) \(viewController) " +
"enabled: \(self.interactivePopGestureRecognizer?.isEnabled)" +
"------")
}
}