Попытка обработать действие кнопки "назад" в iOS

Мне нужно определить, когда пользователь нажимает кнопку "назад" на панели навигации, чтобы выполнять некоторые операции, когда это происходит. Я пытаюсь вручную установить действие на такую ​​кнопку:

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

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

   [self.navigationController popViewControllerAnimated:NO];
}

Я сначала поместил этот код в сам контроллер представления, но обнаружил, что self.navigationItem.backBarButtonItem, казалось, был nil, поэтому я переместил этот же код в родительский контроллер представления, который подталкивает его в стек навигации. Но я не могу заставить его работать. Я прочитал несколько сообщений по этой проблеме, и некоторые из них сказали, что селектор должен быть установлен в родительском контроллере представления, но для меня это все равно не работает... Что я могу сделать неправильно?

Спасибо

Ответ 1

Попробуйте использовать этот код с помощью метода 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];
}

ИЛИ Существует другой способ получить действие кнопки "Навигация" BAck.

Создать пользовательскую кнопку для кнопки UINavigationItem для возврата.

Для Ex:

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

Swift:

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

Ответ 2

Swift

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

Ответ 3

Возможно, эти ответы не соответствуют вашему объяснению, но заголовок вопроса. Это полезно, когда вы пытаетесь узнать, когда вы нажали кнопку "Назад" на 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, потому что поп-анимирован, и я хотел сразу обращаться к кнопке "Назад" и не ждать завершения перехода.

Ответ 4

Проблема с didMoveToParentViewController, которую он вызывает, после того, как родительский вид будет полностью виден, поэтому, если вам нужно выполнить некоторые задачи до этого, это не сработает.

И это не работает с движением жесты анимации. Использование willMoveToParentViewController работает лучше.

Objective-c

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

Swift

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

Ответ 5

Это Objective-C версия dadachi's Ответ:

Objective-C

- (void)didMoveToParentViewController:(UIViewController *)parent{
    if (parent == NULL) {
        NSLog(@"Back Pressed");
    }
}

Ответ 6

Установите делегат UINavigationBar, а затем используйте:

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

Ответ 7

Установите 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
    }
}

Ответ 8

Ни один из других решений не работал для меня, но это делает:

Создайте свой собственный подкласс UINavigationController, внесите его в UINavigationBarDelegate (нет необходимости вручную устанавливать делегат панели навигации), добавьте расширение UIViewController, которое определяет метод, который будет вызываться при нажатии кнопки "Назад", а затем реализовать этот метод в вашем подклассе UINavigationController:

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

Ответ 9

Используйте пользовательский подкласс UINavigationController, который реализует метод shouldPop.

В Свифте:

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(), чтобы решить, будет ли контроллер всплывающим или нет. Когда он не установлен, он просто выскочит как обычно.

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

Ответ 10

В Swift 4 или выше:

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