No Swipe Back when hiding Navigation Bar in UINavigationController

前端 未结 18 677
生来不讨喜
生来不讨喜 2020-12-04 06:34

I love the swipe pack thats inherited from embedding your views in a UINavigationController. Unfortunately i cannot seem to find a way to hide the Naviga

相关标签:
18条回答
  • 2020-12-04 06:44

    Looks like solution provided by @ChrisVasseli is the best. I'd like to provide same solution in Objective-C because question is about Objective-C (see tags)

    @interface InteractivePopGestureDelegate : NSObject <UIGestureRecognizerDelegate>
    
    @property (nonatomic, weak) UINavigationController *navigationController;
    @property (nonatomic, weak) id<UIGestureRecognizerDelegate> originalDelegate;
    
    @end
    
    @implementation InteractivePopGestureDelegate
    
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
    {
        if (self.navigationController.navigationBarHidden && self.navigationController.viewControllers.count > 1) {
            return YES;
        } else {
            return [self.originalDelegate gestureRecognizer:gestureRecognizer shouldReceiveTouch:touch];
        }
    }
    
    - (BOOL)respondsToSelector:(SEL)aSelector
    {
        if (aSelector == @selector(gestureRecognizer:shouldReceiveTouch:)) {
            return YES;
        } else {
            return [self.originalDelegate respondsToSelector:aSelector];
        }
    }
    
    - (id)forwardingTargetForSelector:(SEL)aSelector
    {
        return self.originalDelegate;
    }
    
    @end
    
    @interface NavigationController ()
    
    @property (nonatomic) InteractivePopGestureDelegate *interactivePopGestureDelegate;
    
    @end
    
    @implementation NavigationController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        self.interactivePopGestureDelegate = [InteractivePopGestureDelegate new];
        self.interactivePopGestureDelegate.navigationController = self;
        self.interactivePopGestureDelegate.originalDelegate = self.interactivePopGestureRecognizer.delegate;
        self.interactivePopGestureRecognizer.delegate = self.interactivePopGestureDelegate;
    }
    
    @end
    
    0 讨论(0)
  • 2020-12-04 06:52

    In my view controller without navigationbar I use

    open override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(animated)
    
      CATransaction.begin()
      UIView.animate(withDuration: 0.25, animations: { [weak self] in
        self?.navigationController?.navigationBar.alpha = 0.01
      })
      CATransaction.commit()
    }
    
    open override func viewWillDisappear(_ animated: Bool) {
      super.viewWillDisappear(animated)
      CATransaction.begin()
      UIView.animate(withDuration: 0.25, animations: { [weak self] in
        self?.navigationController?.navigationBar.alpha = 1.0
      })
      CATransaction.commit()
    }
    

    During the interactive dismissal the back button will shine through though, which is why I hid it.

    0 讨论(0)
  • 2020-12-04 06:57

    My solution is to directly extend the UINavigationController class :

    import UIKit
    
    extension UINavigationController: UIGestureRecognizerDelegate {
    
        override open func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
    
            self.interactivePopGestureRecognizer?.delegate = self
        }
    
        public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
            return self.viewControllers.count > 1
        }
    
    }
    

    This way, all navigation controllers will be dismissable by sliding.

    0 讨论(0)
  • 2020-12-04 06:58

    A hack that is working is to set the interactivePopGestureRecognizer's delegate of the UINavigationController to nil like this:

    [self.navigationController.interactivePopGestureRecognizer setDelegate:nil];
    

    But in some situations it could create strange effects.

    0 讨论(0)
  • 2020-12-04 06:58

    I've tried this and it's working perfectly : How to hide Navigation Bar without losing slide-back ability

    The idea is to implement "UIGestureRecognizerDelegate" in your .h and add this to your .m file.

    - (void)viewWillAppear:(BOOL)animated {
    // hide nav bar
    [[self navigationController] setNavigationBarHidden:YES animated:YES];
    
    // enable slide-back
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.navigationController.interactivePopGestureRecognizer.enabled = YES;
        self.navigationController.interactivePopGestureRecognizer.delegate = self;
      }
    }
    
    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
       return YES;  
    }
    
    0 讨论(0)
  • 2020-12-04 07:00

    Simple, no side-effect Answer

    While most answers here are good, they seemingly have unintended side-effects (app breaking) or are verbose.

    The most simple yet functional solution I could come up with was the following:

    In the ViewController that you are hiding the navigationBar,

    class MyNoNavBarViewController: UIViewController {
        
        // needed for reference when leaving this view controller
        var initialInteractivePopGestureRecognizerDelegate: UIGestureRecognizerDelegate?
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // we will need a reference to the initial delegate so that when we push or pop.. 
            // ..this view controller we can appropriately assign back the original delegate
            initialInteractivePopGestureRecognizerDelegate = self.navigationController?.interactivePopGestureRecognizer?.delegate
        }
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(true)
    
            // we must set the delegate to nil whether we are popping or pushing to..
            // ..this view controller, thus we set it in viewWillAppear()
            self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
        }
    
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(true)
    
            // and every time we leave this view controller we must set the delegate back..
            // ..to what it was originally
            self.navigationController?.interactivePopGestureRecognizer?.delegate = initialInteractivePopGestureRecognizerDelegate
        }
    }
    

    Other answers have suggested merely setting the delegate to nil. Swiping backwards to the initial view controller on the navigation stack results in all gestures to be disabled. Some sort of oversight, perhaps, of the UIKit/UIGesture devs.

    As well, some answers here that I have implemented resulted in non-standard apple navigation behaviour (specifically, allowing for the ability to scroll up or down while also swiping backwards). These answers also seem a bit verbose and in some cases incomplete.

    0 讨论(0)
提交回复
热议问题