обратный вызов кнопки в navigationController в iOS


Я нажал вид на навигационный контроллер, и когда я нажимаю кнопку назад, он автоматически переходит к предыдущему виду. Я хочу сделать несколько вещей, когда кнопка Назад нажата, прежде чем выскакивать вид из стека. Какая функция обратного вызова кнопки Назад?

11 93

11 ответов:

Уильяма Джокуша ответ решить эту проблему с помощью простого трюка.

-(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];
}

на мой взгляд лучшее решение.

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

но он работает только с iOS5+

вероятно, лучше переопределить заднюю кнопку, чтобы вы могли обрабатывать событие до вид выскочил для таких вещей, как подтверждение пользователя.

в 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 для выполнения действий при нажатии кнопки "Назад".

Я в конечном итоге с помощью этого решения. Когда мы нажимаем кнопку Назад, вызывается метод 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];

    }
}

Для "перед выскакиванием вида из стека":

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

есть более подходящий способ, чем спрашивать viewControllers. Вы можете сделать свой контроллер делегатом панели навигации, которая имеет кнопку Назад. Вот вам пример. В реализации контроллера, где вы хотите обработать нажатие кнопки Назад, скажите ему, что он будет реализовывать протокол UINavigationBarDelegate:

@interface MyViewController () <UINavigationBarDelegate>

затем где-то в вашем коде инициализации (вероятно, в viewDidLoad) сделайте свой контроллер делегатом его навигации бар:

self.navigationController.navigationBar.delegate = self;

наконец, реализовать метод shouldPopItem. Этот метод вызывается прямо при нажатии кнопки Назад. Если у вас есть несколько контроллеров или элементов навигации в стеке, вы, вероятно, захотите проверить, какой из этих элементов навигации появляется (параметр item), так что вы только делаете свои собственные вещи, когда ожидаете. Вот пример:

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

это правильный способ обнаружить это.

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

    }
}

этот метод вызывается также при нажатии view. Поэтому проверка parent==nil предназначена для выскакивания контроллера вида из стека

Если вы не можете использовать "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;
    }
}

вот еще один способ, который я реализовал (не тестировал его с помощью unwind segue, но он, вероятно, не отличался бы, как другие заявили в отношении других решений на этой странице), чтобы родительский контроллер представления выполнял действия до того, как дочерний VC, который он нажал, будет удален из стека представления (я использовал это на пару уровней ниже от исходного UINavigationController). Это также может быть использовано для выполнения действий до того, как childVC будет нажата. Это имеет дополнительное преимущество работы с помощью кнопки iOS system back, вместо того, чтобы создавать пользовательский 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 (i.e., 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;
    

    }

Если вы используете раскадровку, и вы исходите из push segue, вы также можете просто переопределить shouldPerformSegueWithIdentifier:sender:.

вот что он работает для меня в Swift:

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

    super.viewWillDisappear(animated)
}