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

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

Ответ 1

William Jockusch answer решить эту проблему с помощью простого трюка.

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

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 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];

    }
}

Ответ 5

Для "ПЕРЕД ВЫПОЛНЕНИЕМ представления из стека":

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

Ответ 6

Там более подходящий способ, чем запрос 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;
}

Ответ 7

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

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

    }
}

этот метод вызывается, когда вид также сдвигается. Таким образом, проверка parent == nil - это вызов диспетчера представлений из стека

Ответ 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 с вашим настраиваемым навигационным контроллером, поэтому в вашем методе viewDidLoad для вашего обычного диспетчера viewController выполните следующее:

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

Ответ 9

Здесь другой способ, который я реализовал (не тестировал его с помощью unind segue, но он, вероятно, не будет отличать, как другие заявили в отношении других решений на этой странице), чтобы контроллер родительского представления выполнял действия до того, как ребенок VC, который он нажал, выскочил из стека представлений (я использовал это на пару уровней от исходного UINavigationController). Это также можно использовать для выполнения действий до того, как будет запущен childVC. Это имеет дополнительное преимущество в работе с кнопкой возврата системы iOS вместо создания пользовательского UIBarButtonItem или UIButton.

  • Попросите вашего родителя VC принять протокол UINavigationControllerDelegate и зарегистрировать для сообщений делегатов:

    MyParentViewController : UIViewController <UINavigationControllerDelegate>
    
    -(void)viewDidLoad {
        self.navigationcontroller.delegate = self;
    }
    
  • Внедрите этот метод экземпляра 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 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;
    }
    
  • Если вы укажете определенную функцию обратного вызова в приведенном выше методе 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;
    

    }

Ответ 10

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

Ответ 11

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

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

    super.viewWillDisappear(animated)
}