127

を使用してモーダルビューコントローラを閉じる場合dismissViewController、完了ブロックを提供するオプションがあります。同様の同等物はありpopViewControllerますか?

完了引数は非常に便利です。たとえば、モーダルが画面外になるまでテーブルビューから行を削除しないようにするために使用して、ユーザーに行のアニメーションを表示させることができます。プッシュされたビューコントローラから戻るときも、同じ機会が欲しいです。

完了ブロックにアクセスできるアニメーションブロックに配置popViewControllerしてみました。UIViewただし、これにより、ポップされるビューにいくつかの望ましくない副作用が発生します。

そのような方法が利用できない場合、いくつかの回避策はありますか?

4

21 に答える 21

65

Swift 5 バージョン - 魅力的に動作します。この回答に基づいて

extension UINavigationController {
    func pushViewController(viewController: UIViewController, animated: Bool, completion: @escaping () -> Void) {
        pushViewController(viewController, animated: animated)

        if animated, let coordinator = transitionCoordinator {
            coordinator.animate(alongsideTransition: nil) { _ in
                completion()
            }
        } else {
            completion()
        }
    }

    func popViewController(animated: Bool, completion: @escaping () -> Void) {
        popViewController(animated: animated)

        if animated, let coordinator = transitionCoordinator {
            coordinator.animate(alongsideTransition: nil) { _ in
                completion()
            }
        } else {
            completion()
        }
    }
}
于 2016-04-23T10:51:31.677 に答える
17

同じ問題がありました。複数の場面で使用する必要があり、完了ブロックのチェーン内で使用する必要があったため、UINavigationController サブクラスでこの汎用ソリューションを作成しました。

- (void) navigationController:(UINavigationController *) navigationController didShowViewController:(UIViewController *) viewController animated:(BOOL) animated {
    if (_completion) {
        dispatch_async(dispatch_get_main_queue(),
        ^{
            _completion();
            _completion = nil;
         });
    }
}

- (UIViewController *) popViewControllerAnimated:(BOOL) animated completion:(void (^)()) completion {
    _completion = completion;
    return [super popViewControllerAnimated:animated];
}

仮定

@interface NavigationController : UINavigationController <UINavigationControllerDelegate>

@implementation NavigationController {
    void (^_completion)();
}

- (id) initWithRootViewController:(UIViewController *) rootViewController {
    self = [super initWithRootViewController:rootViewController];
    if (self) {
        self.delegate = self;
    }
    return self;
}
于 2013-12-13T11:48:02.523 に答える
15

すぐに使用できる方法はありません。つまり、ナビゲーション スタックからビュー コントローラーをポップするための完了ブロックを持つメソッドはありません。

私がすることは、ロジックを に入れることですviewDidAppear。これは、ビューが画面に表示され終わったときに呼び出されます。ビューコントローラーが表示されるすべての異なるシナリオで呼び出されますが、それで問題ありません。

または、UINavigationControllerDelegateメソッドnavigationController:didShowViewController:animated:を使用して同様のことを行うこともできます。これは、ナビゲーション コントローラーがビュー コントローラーのプッシュまたはポップを終了したときに呼び出されます。

于 2012-10-15T21:39:44.063 に答える
15

アニメーションの有無にかかわらず適切に作業し、以下も含まれますpopToRootViewController

 // updated for Swift 3.0
extension UINavigationController {

  private func doAfterAnimatingTransition(animated: Bool, completion: @escaping (() -> Void)) {
    if let coordinator = transitionCoordinator, animated {
      coordinator.animate(alongsideTransition: nil, completion: { _ in
        completion()
      })
    } else {
      DispatchQueue.main.async {
        completion()
      }
    }
  }

  func pushViewController(viewController: UIViewController, animated: Bool, completion: @escaping (() ->     Void)) {
    pushViewController(viewController, animated: animated)
    doAfterAnimatingTransition(animated: animated, completion: completion)
  }

  func popViewController(animated: Bool, completion: @escaping (() -> Void)) {
    popViewController(animated: animated)
    doAfterAnimatingTransition(animated: animated, completion: completion)
  }

  func popToRootViewController(animated: Bool, completion: @escaping (() -> Void)) {
    popToRootViewController(animated: animated)
    doAfterAnimatingTransition(animated: animated, completion: completion)
  }
}
于 2016-09-06T14:51:48.170 に答える
5

この回答のおかげで、Swift 3の回答: https://stackoverflow.com/a/28232570/3412567

    //MARK:UINavigationController Extension
extension UINavigationController {
    //Same function as "popViewController", but allow us to know when this function ends
    func popViewControllerWithHandler(completion: @escaping ()->()) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        self.popViewController(animated: true)
        CATransaction.commit()
    }
    func pushViewController(viewController: UIViewController, completion: @escaping ()->()) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        self.pushViewController(viewController, animated: true)
        CATransaction.commit()
    }
}
于 2016-11-09T08:06:27.747 に答える
5

提示されたView ControllerでviewDidDisappearメソッドが呼び出された後に完了ブロックが呼び出されるため、ポップされたView ControllerのviewDidDisappearメソッドにコードを配置すると、完了ブロックと同じように機能するはずです。

于 2012-10-15T21:51:51.300 に答える
2

コードで次の拡張機能を使用します: (Swift 4)

import UIKit

extension UINavigationController {

    func popViewController(animated: Bool = true, completion: @escaping () -> Void) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        popViewController(animated: animated)
        CATransaction.commit()
    }

    func pushViewController(_ viewController: UIViewController, animated: Bool = true, completion: @escaping () -> Void) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        pushViewController(viewController, animated: animated)
        CATransaction.commit()
    }
}
于 2018-01-04T21:42:55.283 に答える
1

完全を期すために、Objective-C カテゴリをすぐに使用できるようにしました。

// UINavigationController+CompletionBlock.h

#import <UIKit/UIKit.h>

@interface UINavigationController (CompletionBlock)

- (UIViewController *)popViewControllerAnimated:(BOOL)animated completion:(void (^)()) completion;

@end
// UINavigationController+CompletionBlock.m

#import "UINavigationController+CompletionBlock.h"

@implementation UINavigationController (CompletionBlock)

- (UIViewController *)popViewControllerAnimated:(BOOL)animated completion:(void (^)()) completion {
    [CATransaction begin];
    [CATransaction setCompletionBlock:^{
        completion();
    }];

    UIViewController *vc = [self popViewControllerAnimated:animated];

    [CATransaction commit];

    return vc;
}

@end
于 2015-11-27T12:15:18.423 に答える
0

2021 年、Swift 5

extension UINavigationController {
func pushViewController(viewController: UIViewController, animated: Bool, completion: @escaping() -> ()) {
    pushViewController(viewController, animated: animated)
    
    if let coordinator = transitionCoordinator, animated {
        coordinator.animate(alongsideTransition: nil) { _ in
            completion()
        }
    } else {
        completion()
    }
}

func popViewController(animated: Bool, completion: @escaping() -> ()) {
    popViewController(animated: animated)
    
    if let coordinator = transitionCoordinator, animated {
        coordinator.animate(alongsideTransition: nil) { _ in
            completion()
        }
    } else {
        completion()
    }
}
}
于 2021-09-30T05:48:15.237 に答える