This is the 17th day of my participation in the August More Text Challenge. For details, see “August More Text Challenge” juejin.cn/post/698796…

The introduction

Return gestures interactivePopGestureRecognizer principle: the use of system implementation

Usage scenario: If the back button is too small to trigger the return button, you can use the right swipe to return button to improve the user experience

I, added the swipe right back gesture

If the project has a global UINavigationController base class, add a right swipe back gesture to the page

@implementation NavigationController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Set the proxy for the right swipe back gesture to itself
    __weak typeof(self) weakself = self;
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.delegate = (id)weakself; }}#pragma mark - UIGestureRecognizerDelegate
// This method is called before the gesture is about to be activated: returns YES to allow right-swipe activation, and NO to disallow right-swipe activation
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer == self.interactivePopGestureRecognizer) {
        // Mask the swipe back gesture of calling rootViewController to avoid the crash problem caused by the right swipe back gesture
        if (self.viewControllers.count < 2 ||
 self.visibleViewController == [self.viewControllers objectAtIndex:0]) {
            return NO; }}// This is the method called by a non-right swipe gesture
    return YES;
}
Copy the code

II. The solution does not take effect when you swipe right due to QMUI

Let’s see how QMUI is implemented to achieve the right slip back?

2.1 UINavigationController (QMUI) Control the right slide back

QMUI uses the classified UINavigationController (QMUI) mode to control the right slide back. The specific core code is as follows

  1. Override viewDidLoad to set the right slide back gesture proxy to itself
        ExtendImplementationOfVoidMethodWithoutArguments([UINavigationController class].@selector(viewDidLoad), ^(UINavigationController *selfObject) {
            selfObject.qmui_interactivePopGestureRecognizerDelegate = selfObject.interactivePopGestureRecognizer.delegate;
            selfObject.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)selfObject;
        });


Copy the code
  1. gestureRecognizerShouldBegin

This method is called just before the gesture is about to be activated: returns YES for right-swiping and NO for right-swiping

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer == self.interactivePopGestureRecognizer) {
        BOOL canPopViewController = [self canPopViewController:self.topViewController byPopGesture:YES];
        if (canPopViewController) {
            if ([self.qmui_interactivePopGestureRecognizerDelegate respondsToSelector:_cmd]) {
                return [self.qmui_interactivePopGestureRecognizerDelegate gestureRecognizerShouldBegin:gestureRecognizer];
            } else {
                return NO; }}else {
            return NO; }}return YES;
}


Copy the code
  1. IOS 13.4 starts with a priority queryshouldReceiveEventMethod, which will continue the logic only if it returns YES

- (BOOL)_gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveEvent:(UIEvent *)event {
    if (gestureRecognizer == self.interactivePopGestureRecognizer) {
        NSObject <UIGestureRecognizerDelegate> *originGestureDelegate = self.qmui_interactivePopGestureRecognizerDelegate;
        if ([originGestureDelegate respondsToSelector:_cmd]) {
            BOOL originalValue = YES;
            [originGestureDelegate qmui_performSelector:_cmd withPrimitiveReturnValue:&originalValue arguments:&gestureRecognizer, &event, nil];
            if(! originalValue && [self shouldForceEnableInteractivePopGestureRecognizer]) {
                return YES;
            }
            returnoriginalValue; }}return YES;
}


Copy the code

In the third stepshouldForceEnableInteractivePopGestureRecognizerCall the UINavigationControllerBackButtonHandlerProtocol agreementforceEnableInteractivePopGestureRecognizerTo determine whether to return.

- (BOOL)shouldForceEnableInteractivePopGestureRecognizer {
    UIViewController *viewController = [self topViewController];
    return self.viewControllers.count > 1 && self.interactivePopGestureRecognizer.enabled && [viewController respondsToSelector:@selector(forceEnableInteractivePopGestureRecognizer)] && [viewController forceEnableInteractivePopGestureRecognizer];
}

Copy the code

When you customize the leftBarButtonItem button, the system’s gesture return is disabled.

Can be decided through forceEnableInteractivePopGestureRecognizer back do you want to add the gestures to return force. When interactivePopGestureRecognizer. Enabled = NO or current UINavigationController stack viewControllers less than 2 when this method is invalid.

Custom leftBarButtonItem button

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
    
    viewController.hidesBottomBarWhenPushed = self.viewControllers.count == 1;

    
    if (self.viewControllers.count>0) {[self setNavigationBarHidden:NO animated:NO];
// viewController.hidesBottomBarWhenPushed =YES;
        // Set the left button

        UIBarButtonItem *backItem      =nil;
        
        
        if ([viewController respondsToSelector:@selector(KNbackAction)]) {

             backItem =[[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:QCTNAVicon_left] style:0 target:viewController action:@selector(KNbackAction)];
            

            
            
        }else{
            
            backItem =[[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:QCTNAVicon_left] style:0 target:self action:@selector(backAction)];

            
            
        }
        
            viewController.navigationItem.leftBarButtonItems = @[backItem];


        



        
        
    }
    [super pushViewController:viewController animated:animated];

}

Copy the code

2.2 Solutions

So when you customize the navigationBar (the leftBarButtonItem button) without using the system’s default implementation, you can first check why the system does not allow your gesture to return, such as hidden navigationBar, or hidden system back button?

Such as push, custom leftBarButtonItem button, you can use classification to add forceEnableInteractivePopGestureRecognizer UIViewController method will return to mandatory gestures add back

2.3 Dynamic Adding Methods

Usage scenario:

  1. The dynamic addition method is used for message sending and message forwarding
  2. Global control returns a gesture

The following +addMethod method takes three arguments. The first argument is the class to which the method is to be added, the second argument is the SEL of the method, and the third argument is the SEL that provides the method implementation.

Use class_getInstanceMethod() and method_getImplementation() to get the corresponding SEL.

The IMP is an acronym for Implementation. After getting the corresponding method Implementation, you can bind IMP to SEL by calling class_addMethod().


/** Add new method to class @param methodSel @param methodSelImpl contains SEL */
+ (void)addMethod:(Class)class method:(SEL)methodSel method:(SEL)methodSelImpl {
    Method method = class_getInstanceMethod(class, methodSelImpl);
    IMP methodIMP = method_getImplementation(method);
    const char *types = method_getTypeEncoding(method);
    class_addMethod(class, methodSel, methodIMP, types);
}

Copy the code

Add forceEnableInteractivePopGestureRecognizer UIViewController method will return to mandatory gestures add back

    @implementation UIViewController (ERPPresent13)
+ (void)load {

    [self addMethod:self.class method:@selector(forceEnableInteractivePopGestureRecognizer) method:@selector(kunnan_forceEnableInteractivePopGestureRecognizer)];
    
    
}

- (BOOL)kunnan_forceEnableInteractivePopGestureRecognizer {

    
    return YES;
    


}



Copy the code

III. Customize the rightBarButtonItem of the navigation bar

Custom navigation rightBarButtonItem, adopting initWithCustomView: rightBtn set rightBtn. Frame, make the text more, are more likely to click

Kunnan.blog.csdn.net/article/det…

- (void) setuprightBtn{
    
    
    UIButton *rightBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    rightBtn.frame = CGRectMake(0.0.44.44);
// [rightBtn setImage:[UIImage imageNamed:@"icon_shoukuan_shaixuan_n"] forState:UIControlStateNormal];
    [rightBtn setTitle:@ "edit" forState:UIControlStateNormal];
    
    [rightBtn setTitleColor:kcellColor forState:UIControlStateNormal];

    [rightBtn addTarget:self action:@selector(gotoEditVC) forControlEvents:UIControlEventTouchUpInside];
    [rightBtn setImageEdgeInsets:UIEdgeInsetsMake(0.22.0.0)];
    
    UIBarButtonItem *rightButtonItem = [[UIBarButtonItem alloc]initWithCustomView:rightBtn];
    
    
    self.navigationItem.rightBarButtonItem = rightButtonItem;

    self.navigationItem.rightBarButtonItem.customView.hidden = YES;



}


Copy the code

see also

Thanks for your support, for more content, please pay attention to the official account: iOS Reverse

IOS runtime API app:

1. Implement routing (interface control app to jump to any interface)

2. Obtain the member properties of the modified object

3, dynamic add/exchange method implementation

4. Attribute association

Kunnan.blog.csdn.net/article/det…