Настройка действия кнопки «Назад» в контроллере навигации - PullRequest
175 голосов
/ 01 августа 2009

Я пытаюсь переписать действие по умолчанию кнопки «Назад» в контроллере навигации. Я предоставил цели действие на пользовательской кнопке. Странно то, что при назначении его через атрибут backbutton он не обращает на них внимания, а просто выводит текущее представление и возвращается к корню:

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] 
                                  initWithTitle: @"Servers" 
                                  style:UIBarButtonItemStylePlain 
                                  target:self 
                                  action:@selector(home)];
self.navigationItem.backBarButtonItem = backButton;

Как только я установлю его через leftBarButtonItem на navigationItem, он вызовет мое действие, однако тогда кнопка будет выглядеть как круглая, а не как стрелка назад:

self.navigationItem.leftBarButtonItem = backButton;

Как я могу заставить его вызвать моё собственное действие, прежде чем вернуться к корневому представлению? Есть ли способ перезаписать обратное действие по умолчанию или есть метод, который всегда вызывается при выходе из представления (viewDidUnload этого не делает)?

Ответы [ 28 ]

1 голос
/ 19 февраля 2013

Чтобы перехватить кнопку Назад, просто закройте ее прозрачным UIControl и перехватите касания.

@interface MyViewController : UIViewController
{
    UIControl   *backCover;
    BOOL        inhibitBackButtonBOOL;
}
@end

@implementation MyViewController
-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // Cover the back button (cannot do this in viewWillAppear -- too soon)
    if ( backCover == nil ) {
        backCover = [[UIControl alloc] initWithFrame:CGRectMake( 0, 0, 80, 44)];
#if TARGET_IPHONE_SIMULATOR
        // show the cover for testing
        backCover.backgroundColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.15];
#endif
        [backCover addTarget:self action:@selector(backCoverAction) forControlEvents:UIControlEventTouchDown];
        UINavigationBar *navBar = self.navigationController.navigationBar;
        [navBar addSubview:backCover];
    }
}

-(void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [backCover removeFromSuperview];
    backCover = nil;
}

- (void)backCoverAction
{
    if ( inhibitBackButtonBOOL ) {
        NSLog(@"Back button aborted");
        // notify the user why...
    } else {
        [self.navigationController popViewControllerAnimated:YES]; // "Back"
    }
}
@end
1 голос
/ 08 ноября 2012

Для формы, которая требует пользовательского ввода, подобного этой, я бы рекомендовал вызывать ее как «модальную» вместо части вашего стека навигации. Таким образом, они должны позаботиться о бизнесе в форме, затем вы можете проверить ее и отклонить с помощью пользовательской кнопки. Вы даже можете создать навигационную панель, которая будет выглядеть так же, как и все остальное в вашем приложении, но даст вам больше контроля.

1 голос
/ 25 мая 2010

Вы можете попробовать получить доступ к элементу правой кнопки NavigationBars и установить его свойство селектора ... вот ссылка Ссылка UIBarButtonItem , еще одна вещь, если эта работа, которая определит работу, - это установить элемент правой кнопки панель навигации для пользовательского UIBarButtonItem, который вы создаете и устанавливаете его селектор ... надеюсь, это поможет

1 голос
/ 30 апреля 2018

Swift 4 iOS 11.3 Версия:

Это основано на ответе от kgaidis от https://stackoverflow.com/a/34343418/4316579

Я не уверен, когда расширение перестало работать, но на момент написания этой статьи (Swift 4) кажется, что расширение больше не будет выполняться, пока вы не объявите соответствие UINavigationBarDelegate, как описано ниже.

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

extension UINavigationController: UINavigationBarDelegate {
    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {

    }
}
1 голос
/ 27 июля 2009

Используя переменные target и action, которые вы в настоящий момент оставляете «nil», вы сможете связать свои диалоги сохранения так, чтобы они вызывались, когда кнопка «выбрана». Будьте осторожны, это может произойти в странные моменты.

Я согласен в основном с Amagrammer, но я не думаю, что было бы так сложно сделать кнопку со стрелкой на заказ. Я просто переименую кнопку «Назад», сделаю снимок экрана, сделаю фотошоп нужного размера кнопки и получу изображение поверх вашей кнопки.

0 голосов
/ 13 июня 2016

Быстрая версия ответа @ onegray

protocol RequestsNavigationPopVerification {
    var confirmationTitle: String { get }
    var confirmationMessage: String { get }
}

extension RequestsNavigationPopVerification where Self: UIViewController {
    var confirmationTitle: String {
        return "Go back?"
    }

    var confirmationMessage: String {
        return "Are you sure?"
    }
}

final class NavigationController: UINavigationController {

    func navigationBar(navigationBar: UINavigationBar, shouldPopItem item: UINavigationItem) -> Bool {

        guard let requestsPopConfirm = topViewController as? RequestsNavigationPopVerification else {
            popViewControllerAnimated(true)
            return true
        }

        let alertController = UIAlertController(title: requestsPopConfirm.confirmationTitle, message: requestsPopConfirm.confirmationMessage, preferredStyle: .Alert)

        alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel) { _ in
            dispatch_async(dispatch_get_main_queue(), {
                let dimmed = navigationBar.subviews.flatMap { $0.alpha < 1 ? $0 : nil }
                UIView.animateWithDuration(0.25) {
                    dimmed.forEach { $0.alpha = 1 }
                }
            })
            return
        })

        alertController.addAction(UIAlertAction(title: "Go back", style: .Default) { _ in
            dispatch_async(dispatch_get_main_queue(), {
                self.popViewControllerAnimated(true)
            })
        })

        presentViewController(alertController, animated: true, completion: nil)

        return false
    }
}

Теперь в любом контроллере просто соответствует RequestsNavigationPopVerification, и это поведение принимается по умолчанию.

0 голосов
/ 11 мая 2015

Решение, которое я нашел до сих пор, не очень хорошее, но оно работает для меня. Принимая этот ответ , я также проверяю, высовываю ли я программно или нет:

- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];

  if ((self.isMovingFromParentViewController || self.isBeingDismissed)
      && !self.isPoppingProgrammatically) {
    // Do your stuff here
  }
}

Вы должны добавить это свойство к своему контроллеру и установить его в YES, прежде чем программно появиться:

self.isPoppingProgrammatically = YES;
[self.navigationController popViewControllerAnimated:YES];
0 голосов
/ 14 июля 2015

Найден новый способ сделать это:

Objective-C

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

Swift

override func didMoveToParentViewController(parent: UIViewController?) {
    if parent == nil {
        println("Back Pressed")
    }
}
...