web-dev-qa-db-ja.com

iOSで「戻る」ナビゲーションボタンアクションを処理しようとする

ユーザーがナビゲーションバーの「戻る」ボタンをタップしたときに、それが発生したときにいくつかの操作を実行するために検出する必要があります。私はこのようなボタンにアクションを手動で設定しようとしています:

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

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

   [self.navigationController popViewControllerAnimated:NO];
}

最初にそのコードをView Controller自体に配置しましたが、self.navigationItem.backBarButtonItemnilであるように見えたため、同じコードを親View Controllerに移動し、前者をNavigation Stackにプッシュしました。しかし、私はそれを機能させることもできません。私はこの問題に関するいくつかの投稿を読みましたが、一部の人はセレクタを親のView Controllerに設定する必要があると言っていましたが、私にとってはそれはうまくいきません...何が間違っているのでしょうか?

ありがとう

69
AppsDev

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

または、Navigation BAckボタンのアクションを取得する別の方法があります。

戻るボタンの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];
}

Swift:

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

Swift

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

おそらく、この回答は説明ではなく質問のタイトルに合っています。 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を使用しました。

16
Firula

didMoveToParentViewControllerの問題は、親ビューが再び完全に表示されると呼び出されるため、その前にいくつかのタスクを実行する必要がある場合、機能しないことです。

また、ドリブンアニメーションジェスチャでは機能しません。 willMoveToParentViewControllerを使用するとより効果的です。

Objective-c

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

スイフト

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

これは、Objective-Cバージョンの dadachi's Answerです:

Objective-C

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

UINavigationBarのデリゲートを設定し、次を使用します。

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

他の解決策はどれも私にとってはうまくいきませんでしたが、これはうまくいきます:

UINavigationControllerの独自のサブクラスを作成し、UINavigationBarDelegateを実装し(ナビゲーションバーのデリゲートを手動で設定する必要はありません)、戻るボタンを押すと呼び出されるメソッドを定義するUIViewController拡張機能を追加し、UINavigationControllerサブクラスにこのメソッドを実装します:

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

UINavigationControllerDelegateを設定し、このデリゲートfunc(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
    }
}
1
mark

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を無効にすることをお勧めします。

0
Rivera

Swift 4以降:

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