popViewController的完成块

Ben*_*ard 105 cocoa-touch uiviewcontroller uiview uiviewanimation ios

当使用时解除模态视图控制器时dismissViewController,可以选择提供完成块.是否有相似的等价物popViewController

完成论证非常方便.例如,我可以使用它来阻止从tableview中删除一行,直到模态关闭屏幕,让用户看到行动画.从推出的视图控制器返回时,我想要同样的机会.

我已经尝试放置popViewController一个UIView动画块,我可以访问完成块.但是,这会对弹出的视图产生一些不必要的副作用.

如果没有这样的方法,有什么办法吗?

Jor*_*ers 186

我知道两年前已经接受了答案,但这个答案是不完整的.

没有办法做你想要开箱即用的东西

这在技术上是正确的,因为UINavigationControllerAPI不提供任何选项.但是,通过使用CoreAnimation框架,可以向底层动画添加完成块:

[CATransaction begin];
[CATransaction setCompletionBlock:^{
    // handle completion here
}];

[self.navigationController popViewControllerAnimated:YES];

[CATransaction commit];
Run Code Online (Sandbox Code Playgroud)

一旦popViewControllerAnimated:结束使用动画,就会调用完成块.此功能自iOS 4开始提供.

  • 是的,这看起来很棒,但似乎不起作用(至少在iOS 8上).完成块立即被调用.可能是因为核心动画与UIView风格动画的混合. (6认同)
  • 我把它放在Swift中的UINavigationController的扩展中:`extension UINavigationController {func popViewControllerWithHandler(handler :() - >()){CATransaction.begin()CATransaction.setCompletionBlock(handler)self.popViewControllerAnimated(true)CATransaction.commit() } (4认同)
  • 这不起作用 (4认同)
  • 过早地添加了+1。应该是-1。这并不能始终如一地工作,这比根本不工作更糟糕。 (3认同)

Hot*_*ard 50

对于iOS9 SWIFT版本 - 就像一个魅力(没有测试过早期版本).基于这个答案

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

        if let coordinator = transitionCoordinator() where animated {
            coordinator.animateAlongsideTransition(nil) { _ in
                completion()
            }
        } else {
            completion()
        }
    }

    func popViewController(animated: Bool, completion: () -> ()) {
        popViewControllerAnimated(animated)

        if let coordinator = transitionCoordinator() where animated {
            coordinator.animateAlongsideTransition(nil) { _ in
                completion()
            }
        } else {
            completion()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Arb*_*tur 30

Swift@JorisKluivers答案制作了一个扩展版本.

动画,是您在完成后这将调用完成关闭pushpop.

extension UINavigationController {
    func popViewControllerWithHandler(completion: ()->()) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        self.popViewControllerAnimated(true)
        CATransaction.commit()
    }
    func pushViewController(viewController: UIViewController, completion: ()->()) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        self.pushViewController(viewController, animated: true)
        CATransaction.commit()
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 16

我遇到过同样的问题.因为我必须在多个场合使用它,并且在完成块的链中,我在UINavigationController子类中创建了这个通用解决方案:

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

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

假设

@interface NavigationController : UINavigationController <UINavigationControllerDelegate>
Run Code Online (Sandbox Code Playgroud)

@implementation NavigationController {
    void (^_completion)();
}
Run Code Online (Sandbox Code Playgroud)

- (id) initWithRootViewController:(UIViewController *) rootViewController {
    self = [super initWithRootViewController:rootViewController];
    if (self) {
        self.delegate = self;
    }
    return self;
}
Run Code Online (Sandbox Code Playgroud)


mat*_*way 15

没有办法做你想要开箱即用的东西.即,没有用于从导航堆栈弹出视图控制器的完成块的方法.

我要做的就是把逻辑放进去viewDidAppear.当视图完成屏幕时,将调用该方法.它将被视为出现视图控制器的所有不同场景,但这应该没问题.

或者您可以使用该UINavigationControllerDelegate方法navigationController:didShowViewController:animated:执行类似的操作.当导航控制器完成推送或弹出视图控制器时调用此方法.

  • 这个答案并不完全正确.虽然您不能像`-dismissViewController:animated:completionBlock:`那样设置新样式块,但您可以通过导航控制器的委托获取动画.动画完成后,`-navigationController:didShowViewController:animated:`将在委托上调用,你可以在那里做任何你需要的事情. (3认同)

rsh*_*hev 13

正确使用或不使用动画,还包括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)
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 当使用协调器进行动画处理时,“completion”永远不会在同一个运行循环上执行。这保证了“completion”在不设置动画时永远不会在同一个运行循环上运行。最好不要出现这种不一致的情况。 (2认同)

Muh*_*qas 12

SWIFT 4.1

extension UINavigationController {
func pushToViewController(_ viewController: UIViewController, animated:Bool = true, completion: @escaping ()->()) {
    CATransaction.begin()
    CATransaction.setCompletionBlock(completion)
    self.pushViewController(viewController, animated: animated)
    CATransaction.commit()
}

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

func popToViewController(_ viewController: UIViewController, animated:Bool = true, completion: @escaping ()->()) {
    CATransaction.begin()
    CATransaction.setCompletionBlock(completion)
    self.popToViewController(viewController, animated: animated)
    CATransaction.commit()
}

func popToRootViewController(animated:Bool = true, completion: @escaping ()->()) {
    CATransaction.begin()
    CATransaction.setCompletionBlock(completion)
    self.popToRootViewController(animated: animated)
    CATransaction.commit()
}
}
Run Code Online (Sandbox Code Playgroud)


Vit*_*lii 8

基于@ HotJard的答案,当你想要的只是几行代码.快捷方便.

斯威夫特4:

_ = self.navigationController?.popViewController(animated: true)
self.navigationController?.transitionCoordinator.animate(alongsideTransition: nil) { _ in
    doWantIWantAfterContollerHasPopped()
}
Run Code Online (Sandbox Code Playgroud)


d4R*_*4Rk 6

根据这个答案清理了Swift 4版本

extension UINavigationController {
    func pushViewController(_ viewController: UIViewController, animated: Bool, completion: @escaping () -> Void) {
        self.pushViewController(viewController, animated: animated)
        self.callCompletion(animated: animated, completion: completion)
    }

    func popViewController(animated: Bool, completion: @escaping () -> Void) -> UIViewController? {
        let viewController = self.popViewController(animated: animated)
        self.callCompletion(animated: animated, completion: completion)
        return viewController
    }

    private func callCompletion(animated: Bool, completion: @escaping () -> Void) {
        if animated, let coordinator = self.transitionCoordinator {
            coordinator.animate(alongsideTransition: nil) { _ in
                completion()
            }
        } else {
            completion()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


rde*_*mar 5

在呈现的视图控制器上调用 viewDidDisappear 方法之后调用完成块,因此将代码放入弹出视图控制器的 viewDidDisappear 方法中应该与完成块相同。


Ben*_*bab 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()
    }
}
Run Code Online (Sandbox Code Playgroud)


Fat*_*tie 5

对于2018年...

如果你有这个...

    navigationController?.popViewController(animated: false)
    nextStep()
Run Code Online (Sandbox Code Playgroud)

而你想添加一个完成...

    CATransaction.begin()
    navigationController?.popViewController(animated: true)
    CATransaction.setCompletionBlock({ [weak self] in
       self?.nextStep() })
    CATransaction.commit()
Run Code Online (Sandbox Code Playgroud)

就这么简单。


Dra*_*rry 5

请参考最新版本(5.1)的Swifty和类似SDK的方式,

extension UINavigationController {
    func popViewController(animated: Bool, completion: (() -> ())? = nil) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        popViewController(animated: animated)
        CATransaction.commit()
    }
    func pushViewController(_ viewController: UIViewController, animated: Bool, completion: (() -> ())? = nil) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        pushViewController(viewController, animated: animated)
        CATransaction.commit()
    }
}
Run Code Online (Sandbox Code Playgroud)