github download link
The system gesture is added to the view of the navigation controller to realize full screen return. Many people will have many special needs in the visual project,
1: The model comes out with a navigation controller. I think when the sideslip reaches the root controller, the sideslip will be dissmiss
2: If the controller has a scroll view with a long horizontal direction, and the sideslip gesture fails, I need to deal with this
3: Sideslip gestures in a single controller can be disabled
3: The return button is written in the navigation controller, and I want to get the method to transfer when I click the return button
#import <UIKit/UIKit.h> @interface QDNavigationController : UINavigationController //Root controller left edge right sliding dissmiss default yes @property (nonatomic, assign) BOOL needDissMiss; /* The sub controller writes the following method to turn off full screen return reture NO Turn off the full screen return effect of the current page turn on full screen return by default - (BOOL)QDNavigationControllerEnabled{ return NO; } pop Or when dismiss is, call return NO to cancel destroying the page. If you don't cancel destroying the page, return YES; - (BOOL)QDNavigationControllerWillGoBack{ return YES; } */ @end //Screen width #define kScreenWidth [UIScreen mainScreen].bounds.size.width //Screen height #define kScreenHeight [UIScreen mainScreen].bounds.size.height #import "QDNavigationController.h" @interface QDNavigationController ()<UIGestureRecognizerDelegate> //Drag gesture @property (weak, nonatomic) UIPanGestureRecognizer *pan; @end @implementation QDNavigationController - (void)viewDidLoad{ [super viewDidLoad]; //navigationBar style self.navigationBar.translucent = NO; self.navigationBar.barTintColor = [UIColor whiteColor]; self.navigationBar.backgroundColor = [UIColor whiteColor]; // [self.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor blackColor]}]; //Add the system sideslip gesture to the navigation controller view NSArray *targets = [self.interactivePopGestureRecognizer valueForKey:@"_targets"]; id targetObjc = targets[0]; id target = [targetObjc valueForKey:@"target"]; NSString *actionStr = @"handleNavigationTransition:"; UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:NSSelectorFromString(actionStr)]; pan.delegate = self; self.pan = pan; [self.view addGestureRecognizer:pan]; //Remove the original edge slide gesture self.interactivePopGestureRecognizer.enabled = NO; self.needDissMiss = YES; } //Is the gesture effective - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ CGPoint point = [gestureRecognizer locationInView:self.view]; //pan gesture or not BOOL isPanGesture = ([self.pan isEqual:gestureRecognizer]); if ([self.pan translationInView:[self.viewControllers lastObject].view].x < 0 || !isPanGesture) { return NO; } UIViewController *viewController = [self.viewControllers lastObject]; //If the sideslip gesture method return NO. is implemented in the sub controller, the gesture does not take effect. - wnundeclared selector ignores the warning #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" if (isPanGesture && [viewController respondsToSelector:@selector(QDNavigationControllerEnabled)]) { if ([viewController performSelector:@selector(QDNavigationControllerEnabled)] == NO) { return NO; } } #pragma clang diagnostic pop //Special processing of qualified ScrollView BOOL hasScroll = NO; //Can I return to full screen BOOL needPop = NO; for (UIView *subVi in [self.viewControllers lastObject].view.subviews) { //This scrollview contains this point. When the content size width is larger than the screen width, the system gesture is blocked by manual pop if ([subVi isKindOfClass:NSClassFromString(@"UIScrollView")] && ((UIScrollView *)subVi).contentSize.width > kScreenWidth ){ hasScroll = YES; //Turn ContentSize of scrollView to frame to determine whether the touchpoint is on scrollView CGSize scrollContentSize = ((UIScrollView *)subVi).contentSize; CGRect contentSizeRect = CGRectMake(0, 0, scrollContentSize.width, scrollContentSize.height); //scrollView can return to full screen on the leftmost touch point of scrollView if ( ((UIScrollView *)subVi).contentOffset.x == 0 && CGRectContainsPoint( contentSizeRect, [self.view convertPoint:point toView:subVi]) ){ [((UIScrollView *)subVi).panGestureRecognizer requireGestureRecognizerToFail:self.pan]; needPop = YES; break; } //Touch point not on scrollView can return to full screen if (hasScroll == YES && !CGRectContainsPoint( contentSizeRect, [self.view convertPoint:point toView:subVi])) { needPop = YES; break; } } } if (self.viewControllers.count > 1 && (hasScroll == NO || needPop == YES)) { if ([self needGoback] == NO) { return NO; }else{ return YES; } }else{ if (self.viewControllers.count == 1 && (hasScroll == NO || needPop == YES) && [self.pan translationInView:[self.viewControllers lastObject].view].x > 2) { //Root controller meets the condition dismiss [self popOrDissMiss]; } return NO; } } - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{ //Sub controller create return button if (self.viewControllers.count >= 1 ) { viewController.hidesBottomBarWhenPushed = YES; viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:[self creatBackButton]]; } [super pushViewController:viewController animated:YES]; } //Return method - (void)popOrDissMiss{ if ([self needGoback] == NO) { return ; } if (self.viewControllers.count == 1 && self.needDissMiss == YES) { [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; return; } [self popViewControllerAnimated:YES]; } //Call the willGoBack method if the self controller complies with the protocol #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" - (BOOL)needGoback{ UIViewController *viewController = [self.viewControllers lastObject]; //Implement QDNavigationControllerWillGoBack method in the controller and return NO to cancel destroying the page if ([viewController respondsToSelector:@selector(QDNavigationControllerWillGoBack)]) { if ([viewController performSelector:@selector(QDNavigationControllerWillGoBack)] == NO) { return NO; } } return YES; } #pragma clang diagnostic pop //Back button - (UIButton *)creatBackButton{ UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 24.0f, 44.0f)]; [backButton setImage:[UIImage imageNamed:@"daylight-btn-left-arrow-normal"] forState:UIControlStateNormal]; [backButton setImage:[UIImage imageNamed:@"daylight-btn-left-arrow-highlighted"] forState:UIControlStateHighlighted]; [backButton addTarget:self action:@selector(popOrDissMiss) forControlEvents:UIControlEventTouchUpInside]; return backButton; } @end