尝试处理iOS中的“后退”导航按钮操作


76

我需要检测用户何时单击导航栏上的“后退”按钮,以便在发生这种情况时执行一些操作。我正在尝试通过以下方式手动将操作设置为此类按钮:

[self.navigationItem.backBarButtonItem setAction:@selector(performBackNavigation:)];

- (void)performBackNavigation:(id)sender
{
   // Do operations

   [self.navigationController popViewControllerAnimated:NO];
}

我首先将该代码放在视图控制器本身中,但是我发现它self.navigationItem.backBarButtonItem似乎是nil,因此我将相同的代码移到了父视图控制器中,后者将前者推到导航堆栈中。但是我都无法使它工作。我已经阅读了有关此问题的一些帖子,其中一些帖子说选择器需要在父视图控制器上进行设置,但是对我来说它还是不起作用...我在做什么错?

谢谢


将所需的代码放在viewWillDisappear中是否足够好?
DogCoffee 2013年

1
在上使用方法UINavigationControllerDelegate
Mike Weller 2013年

@Smick不,不幸的是,这在我的情况下还不够……
AppsDev 2013年

我尝试了@MikeWeller,但无法正常工作
AppsDev 2013年

查看这个问题的答案。我找到的最佳解决方案。stackoverflow.com/questions/1214965/…–
詹姆斯·帕克

Answers:


132

尝试使用以下代码使用VIewWillDisappear方法来检测是否按下了NavigationItem的后退按钮:

-(void) viewWillDisappear:(BOOL)animated
{
    if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) 
    {
        // Navigation button was pressed. Do some stuff 
        [self.navigationController popViewControllerAnimated:NO];
    }
    [super viewWillDisappear:animated];
}

或者还有另一种获取导航按钮的操作的方法。

为后退按钮的UINavigationItem创建自定义按钮。

例如:

在ViewDidLoad中:

- (void)viewDidLoad 
{
    [super viewDidLoad];
    UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:@"Home" style:UIBarButtonItemStyleBordered target:self action:@selector(home:)];
    self.navigationItem.leftBarButtonItem=newBackButton;
}

-(void)home:(UIBarButtonItem *)sender 
{
    [self.navigationController popToRootViewControllerAnimated:YES];
}

斯威夫特:

override func willMoveToParentViewController(parent: UIViewController?) 
{
    if parent == nil 
    {
        // Back btn Event handler
    }
}

3
我认为viewWillDisappear中不需要[self.navigationController popViewControllerAnimated:NO]。
罗伯特·康

2
我觉得这个方法已经不与iOS 8 self.navigationController.viewControllers仅包含一个元素的工作,==自我
塞巴斯蒂安Stormacq

1
@SébastienStormacq为什么这么说?它可以在iOS 8中使用
。–苏健豪

1
如果在ViewWillDisappear中调用此函数,则仅在轻按“后退”按钮时不会调用它。每当弹出VC或按下新的VC时,都会调用该方法
NSNoob

41

迅速

override func didMoveToParentViewController(parent: UIViewController?) {
    if parent == nil {
        //"Back pressed"
    }
}

5
此解决方案的唯一问题是,如果您滑动以返回并改变主意,则将触发该问题。
克里斯·P

18

也许这个答案不适合您的解释,但不适合您的标题。当您想知道何时点击上的后退按钮时,此功能很有用UINavigationBar

在这种情况下,您可以使用UINavigationBarDelegate协议并实现以下方法之一:

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item;

didPopItem方法被调用,那是因为你要么挖后退按钮,或者你使用[UINavigationBar popNavigationItemAnimated:]方法和导航栏确实流行的项目。

现在,如果您想知道是什么动作触发了该didPopItem方法,则可以使用标志。

使用这种方法,我无需手动添加带有箭头图像的左栏按钮项即可使其类似于iOS的后退按钮,并且能够设置我的自定义目标/操作。


让我们来看一个例子:

我有一个具有页面视图控制器和自定义页面指示器视图的视图控制器。我还使用自定义UINavigationBar来显示标题,以了解我在哪一页上,以及使用“后退”按钮返回上一页。而且我还可以滑动到页面控制器上的上一页/下一页。

#pragma mark - UIPageViewController Delegate Methods
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {

    if( completed ) {

        //...

        if( currentIndex > lastIndex ) {

            UINavigationItem *navigationItem = [[UINavigationItem alloc] initWithTitle:@"Some page title"];

            [[_someViewController navigationBar] pushNavigationItem:navigationItem animated:YES];
            [[_someViewController pageControl] setCurrentPage:currentIndex];
        } else {
            _autoPop = YES; //We pop the item automatically from code.
            [[_someViewController navigationBar] popNavigationItemAnimated:YES];
            [[_someViewController pageControl] setCurrentPage:currentIndex];
        }
    }

}

因此,我实现了UINavigationBar委托方法:

#pragma mark - UINavigationBar Delegate Methods
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
    if( !_autoPop ) {
        //Pop by back button tap
    } else {
        //Pop from code
    }

    _autoPop = NO;

    return YES;
}

在这种情况下,我使用shouldPopItem了弹出式动画,因为我想立即处理后退按钮,而不要等到转换完成。


12

问题didMoveToParentViewController在于,一旦父视图再次完全可见,就会被调用,因此,如果您需要在此之前执行一些任务,它将无法正常工作。

它不适用于驱动的​​动画手势。使用willMoveToParentViewController效果更好。

目标c

- (void)willMoveToParentViewController:(UIViewController *)parent{
    if (parent == NULL) {
        // ...
    }
}

迅速

override func willMoveToParentViewController(parent: UIViewController?) {
    if parent == nil {
        // ...  
    }
}


3

设置UINavigationBar的委托,然后使用:

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
    //handle the action here
}

2
如果您使用UINavigationController来管理导航栏,则尝试设置委托会导致异常:“ ***由于未捕获的异常'NSInternalInconsistencyException'终止了应用程序,原因:'无法在控制器管理的UINavigationBar上手动设置委托。 '”。该UINavigationController是委托。这意味着您可以对控制器进行子类化并覆盖UINavigationBarDelegate方法(可能调用super)。
Geoff Hackworth 2014年

但是您不能直接调用super,因为UINavigationController它不公开符合UINavigationBarDelegate,从而导致编译器错误!可能有使用的解决方案UINavigationControllerDelegate
Geoff Hackworth 2014年

2

设置UINavigationControllerDelegate并实现此委托函数(Swift):

func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
    if viewController is <target class> {
        //if the only way to get back - back button was pressed
    }
}

2

没有其他解决方案对我有用,但是这样做:

创建您自己的UINavigationController子类,使其实现UINavigationBarDelegate(无需手动设置导航栏的委托),添加UIViewController扩展,该扩展定义了要在按下后退按钮时调用的方法,然后在您的UINavigationController子类中实现此方法。 :

func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
    self.topViewController?.methodToBeCalledOnBackButtonPress()
    self.popViewController(animated: true)
    return true
}

您能否扩展答案并显示如何在视图控制器中准确使用它。
zeeshan

2

在Swift 4或更高版本中:

override func didMove(toParent parent: UIViewController?) {
    if parent == nil {
        //"Back pressed"
    }
}

1

使用自定义 UINavigationController实现该shouldPop方法子类。

在Swift中:

class NavigationController: UINavigationController, UINavigationBarDelegate
{
    var shouldPopHandler: (() -> Bool)?

    func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool
    {
        if let shouldPopHandler = self.shouldPopHandler, !shouldPopHandler()
        {
            return false
        }
        self.popViewController(animated: true) // Needed!
        return true
    }
}

设置后,您的 shouldPopHandler()将调用来决定是否弹出控制器。如果未设置,它将照常弹出。

禁用UINavigationControllers是个好主意,interactivePopGestureRecognizer因为该手势不会调用您的处理程序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.