后退按钮回调navigationController在iOS版后退按钮回调navigationCon

2019-05-13 09:14发布

我已经推了视图到导航控制器,当我按下返回按钮,它会自动进入到一个视图。 我想这样做的时候后退按钮弹出视图从堆栈之前按下几件事情。 这是后退按钮回调函数?

Answer 1:

威廉Jockusch的回答解决这个问题很容易把戏。

-(void) viewWillDisappear:(BOOL)animated {
    if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
       // back button was pressed.  We know this is true because self is no longer
       // in the navigation stack.  
    }
    [super viewWillDisappear:animated];
}


Answer 2:

在我看来,最好的解决办法。

- (void)didMoveToParentViewController:(UIViewController *)parent
{
    if (![parent isEqual:self.parentViewController]) {
         NSLog(@"Back pressed");
    }
}

但它仅适用于iOS5的+



Answer 3:

它可能会更好覆盖后退按钮使您可以在视图中弹出的东西,如用户确认之前处理该事件。

在viewDidLoad中创建的UIBarButtonItem,并设置self.navigationItem.leftBarButtonItem它传递一个SEL

- (void) viewDidLoad
{
// change the back button to cancel and add an event handler
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@”back”
style:UIBarButtonItemStyleBordered
target:self
action:@selector(handleBack:)];

self.navigationItem.leftBarButtonItem = backButton;
[backButton release];

}
- (void) handleBack:(id)sender
{
// pop to root view controller
[self.navigationController popToRootViewControllerAnimated:YES];

}

然后,你可以做这样的事情引发一个UIAlertView中确认操作,然后弹出视图控制器等。

或者,而不是创建一个新的后退按钮,就可以符合UINavigationController的委托方法按下后退按钮时做的动作。



Answer 4:

我结束了这个解决方案。 当我们点击返回按钮叫方法viewDidDisappear。 我们可以通过调用isMovingFromParentViewController选择器返回true检查。 我们可以通过数据备份(使用代理)。希望这个帮助别人。

-(void)viewDidDisappear:(BOOL)animated{

    if (self.isMovingToParentViewController) {

    }
    if (self.isMovingFromParentViewController) {
       //moving back
        //pass to viewCollection delegate and update UI
        [self.delegateObject passBackSavedData:self.dataModel];

    }
}


Answer 5:

这是为了检测这种正确的方法。

- (void)willMoveToParentViewController:(UIViewController *)parent{
    if (parent == nil){
        //do stuff

    }
}

当视图被推以及调用此方法。 所以,检查父==零是从堆栈弹出视图控制器



Answer 6:

对于“弹出之前的观点从堆栈”:

- (void)willMoveToParentViewController:(UIViewController *)parent{
    if (parent == nil){
        NSLog(@"do whatever you want here");
    }
}


Answer 7:

还有比要求viewControllers一个更合适的方式。 你可以让你的控制器的导航栏的委托具有后退按钮。 下面是一个例子。 在要处理后退按钮的按下,告诉它,它会实现UINavigationBarDelegate协议控制器的实现:

@interface MyViewController () <UINavigationBarDelegate>

然后在某处你的初始化代码(可能是在viewDidLoad中)使您的控制器的导航栏的代表:

self.navigationController.navigationBar.delegate = self;

最后,实现shouldPopItem方法。 当按下后退按钮时,此方法被调用的权利。 如果你有多个控制器或导航项目在堆栈中,你可能要检查它的导航项目的是越来越弹出(项目参数),这样你,只有当你希望做你的自定义的东西。 下面是一个例子:

-(BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
    NSLog(@"Back button got pressed!");
    //if you return NO, the back button press is cancelled
    return YES;
}


Answer 8:

如果你不能用“viewWillDisappear”或类似的方法,试图继承UINavigationController的。 这是头类:

#import <Foundation/Foundation.h>
@class MyViewController;

@interface CCNavigationController : UINavigationController

@property (nonatomic, strong) MyViewController *viewController;

@end

实现类:

#import "CCNavigationController.h"
#import "MyViewController.h"

@implementation CCNavigationController {

}
- (UIViewController *)popViewControllerAnimated:(BOOL)animated {
    @"This is the moment for you to do whatever you want"
    [self.viewController doCustomMethod];
    return [super popViewControllerAnimated:animated];
}

@end

在另一方面,你需要做这个的viewController链接到您的自定义NavigationController,因此,在您的viewDidLoad方法为您定期的viewController:

@implementation MyViewController {
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        ((CCNavigationController*)self.navigationController).viewController = self;
    }
}


Answer 9:

这里的另一种方式我实现了(没带开卷赛格瑞测试,但它可能不会区分,因为人在这个网页上关于其他的解决方案已经说明)有父视图控制器孩子之前执行的操作VC再推被弹出的视图堆栈(我用这几个级别从原来的UINavigationController下)。 这也可以使用childVC被推前执行动作了。 这与IOS系统背面按钮的工作,而不必创建一个自定义的UIBarButtonItem或UIButton的,的额外优势。

  1. 您的父母VC采用UINavigationControllerDelegate协议并注册代表的消息:

     MyParentViewController : UIViewController <UINavigationControllerDelegate> -(void)viewDidLoad { self.navigationcontroller.delegate = self; } 
  2. 实现此UINavigationControllerDelegate在实例方法MyParentViewController

     - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { // Test if operation is a pop; can also test for a push (ie, do something before the ChildVC is pushed if (operation == UINavigationControllerOperationPop) { // Make sure it's the child class you're looking for if ([fromVC isKindOfClass:[ChildViewController class]]) { // Can handle logic here or send to another method; can also access all properties of child VC at this time return [self didPressBackButtonOnChildViewControllerVC:fromVC]; } } // If you don't want to specify a nav controller transition return nil; } 
  3. 如果在上述指定特定的回调函数UINavigationControllerDelegate实例方法

     -(id <UIViewControllerAnimatedTransitioning>)didPressBackButtonOnAddSearchRegionsVC:(UIViewController *)fromVC { ChildViewController *childVC = ChildViewController.new; childVC = (ChildViewController *)fromVC; // childVC.propertiesIWantToAccess go here // If you don't want to specify a nav controller transition return nil; 

    }



Answer 10:

也许这是一个有点晚了,但在此之前我也想相同的行为。 和我一起工作得很顺利在目前在App Store上的应用程序的一个解决方案。 因为我还没有见过有人去用类似的方法,我想在这里分享。 这种解决方案的缺点是,它需要子类UINavigationController 。 虽然使用方法交叉混合可能有助于避免这一点,我没有走那么远。

因此,默认返回按钮实际上是由管理UINavigationBar 。 当用户点击返回按钮, UINavigationBar要求其委托是否应该弹出顶部UINavigationItem通过调用navigationBar(_:shouldPop:)UINavigationController真正落实这一点,但它并没有公开宣布,它采用UINavigationBarDelegate (为什么!?)。 拦截这种情况下,创建的子类UINavigationController ,宣布其符合UINavigationBarDelegate和实施navigationBar(_:shouldPop:) 。 返回true ,如果顶部的项目应该被弹出。 返回false ,如果它应该保持。

有两个问题。 第一个是,你必须调用UINavigationController版本navigationBar(_:shouldPop:)在一些点。 但UINavigationBarController没有公开宣布其符合UINavigationBarDelegate ,试图调用它会导致编译时错误。 我去的解决方案是使用Objective-C的运行时直接得到执行,并调用它。 请让我知道如果任何人有一个更好的解决方案。

另一个问题是, navigationBar(_:shouldPop:)被称为第一通过如下popViewController(animated:)如果用户点击后退按钮。 如果视图控制器通过调用弹出的顺序颠倒popViewController(animated:) 。 在这种情况下,我用一个布尔值来检测,如果popViewController(animated:)之前被调用navigationBar(_:shouldPop:)这意味着用户已拍了拍后退按钮。

另外,我做的一个扩展UIViewController ,让导航控制器要求视图控制器是否应该,如果用户点击后退按钮被弹出。 视图控制器可以返回false和做任何必要的行动,并呼吁popViewController(animated:)以后。

class InterceptableNavigationController: UINavigationController, UINavigationBarDelegate {
    // If a view controller is popped by tapping on the back button, `navigationBar(_:, shouldPop:)` is called first follows by `popViewController(animated:)`.
    // If it is popped by calling to `popViewController(animated:)`, the order reverses and we need this flag to check that.
    private var didCallPopViewController = false

    override func popViewController(animated: Bool) -> UIViewController? {
        didCallPopViewController = true
        return super.popViewController(animated: animated)
    }

    func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
        // If this is a subsequence call after `popViewController(animated:)`, we should just pop the view controller right away.
        if didCallPopViewController {
            return originalImplementationOfNavigationBar(navigationBar, shouldPop: item)
        }

        // The following code is called only when the user taps on the back button.

        guard let vc = topViewController, item == vc.navigationItem else {
            return false
        }

        if vc.shouldBePopped(self) {
            return originalImplementationOfNavigationBar(navigationBar, shouldPop: item)
        } else {
            return false
        }
    }

    func navigationBar(_ navigationBar: UINavigationBar, didPop item: UINavigationItem) {
        didCallPopViewController = false
    }

    /// Since `UINavigationController` doesn't publicly declare its conformance to `UINavigationBarDelegate`,
    /// trying to called `navigationBar(_:shouldPop:)` will result in a compile error.
    /// So, we'll have to use Objective-C runtime to directly get super's implementation of `navigationBar(_:shouldPop:)` and call it.
    private func originalImplementationOfNavigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
        let sel = #selector(UINavigationBarDelegate.navigationBar(_:shouldPop:))
        let imp = class_getMethodImplementation(class_getSuperclass(InterceptableNavigationController.self), sel)
        typealias ShouldPopFunction = @convention(c) (AnyObject, Selector, UINavigationBar, UINavigationItem) -> Bool
        let shouldPop = unsafeBitCast(imp, to: ShouldPopFunction.self)
        return shouldPop(self, sel, navigationBar, item)
    }
}

extension UIViewController {
    @objc func shouldBePopped(_ navigationController: UINavigationController) -> Bool {
        return true
    }
}

而在您查看控制器,实现shouldBePopped(_:) 。 如果不实现此方法,默认行为会随着用户点击后退按钮就像正常尽快弹出视图控制器。

class MyViewController: UIViewController {
    override func shouldBePopped(_ navigationController: UINavigationController) -> Bool {
        let alert = UIAlertController(title: "Do you want to go back?",
                                      message: "Do you really want to go back? Tap on \"Yes\" to go back. Tap on \"No\" to stay on this screen.",
                                      preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: nil))
        alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { _ in
            navigationController.popViewController(animated: true)
        }))
        present(alert, animated: true, completion: nil)
        return false
    }
}

你可以看一下我的演示在这里 。



Answer 11:

这是我的作品在斯威夫特:

override func viewWillDisappear(_ animated: Bool) {
    if self.navigationController?.viewControllers.index(of: self) == nil {
        // back button pressed or back gesture performed
    }

    super.viewWillDisappear(animated)
}


Answer 12:

如果您使用的是故事板,你就从推SEGUE来了,你也可以只覆盖shouldPerformSegueWithIdentifier:sender:



文章来源: back button callback in navigationController in iOS