iOS 7, corrupt UINavigationBar when swiping back fast using the default interactivePopGestureRecognizer

前端 未结 3 1806
我寻月下人不归
我寻月下人不归 2021-01-31 02:50

I have an issue that I\'m stuck on, but I have no idea why it even happens; If I push a detail controller on the stack, and I swipe back very quickly using the default left edge

3条回答
  •  情歌与酒
    2021-01-31 03:10

    Key Concept

    Disable gesture recognizer when pushing view controller, and enable it when view appeared.

    A Common Solution: Subclassing

    You can subclass UINavigationController and UIViewController to prevent corruption.

    MyNavigationController : UINavigationController

    - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        [super pushViewController:viewController animated:animated];
        self.interactivePopGestureRecognizer.enabled = NO; // disable
    }
    

    MyViewController : UIViewController

    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
        self.navigationController.interactivePopGestureRecognizer.enabled = YES; // enable
    }
    

    Problem: Too annoying

    • Need to use MyNavigationController and MyViewController instead of UINavigationController and UIViewController.
    • Need to subclass for UITableViewController, UICollectionViewController, and more.

    A Better Solution: Method Swizzling

    It could be done by swizzling UINavigationController and UIViewController methods. Want to know about method swizzling, visit here.

    Example below uses JRSwizzle that makes method swizzling easy.

    UINavigationController

    + (void)load
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            [self jr_swizzleMethod:@selector(viewDidLoad)
                        withMethod:@selector(hack_viewDidLoad)
                             error:nil];
            [self jr_swizzleMethod:@selector(pushViewController:animated:)
                        withMethod:@selector(hack_pushViewController:animated:)
                             error:nil];
        });
    }
    
    - (void)hack_viewDidLoad
    {
        [self hack_viewDidLoad];
        self.interactivePopGestureRecognizer.delegate = (id)self;
    }
    
    - (void)hack_pushViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        [self hack_pushViewController:viewController animated:animated];
        self.interactivePopGestureRecognizer.enabled = NO;
    }
    

    UIViewController

    + (void)load
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            [self jr_swizzleMethod:@selector(viewDidAppear:)
                        withMethod:@selector(hack_viewDidAppear:)
                             error:nil];
        });
    }
    
    - (void)hack_viewDidAppear:(BOOL)animated
    {
        [self hack_viewDidAppear:animated];
        self.navigationController.interactivePopGestureRecognizer.enabled = YES;
    }
    

    Being Simple: Use Open Source

    SwipeBack

    SwipeBack does it automatically without any code.

    With CocoaPods, just add a line below into your Podfile. You don't need to write any code. CocoaPods automatically import SwipeBack globally.

    pod 'SwipeBack'

    Install pod, and it's done!

提交回复
热议问题