检测呈现的视图控制器何时被解除

use*_*234 53 uiviewcontroller ios

假设我有一个名为VC2的视图控制器类的实例.在VC2中,有一个"取消"按钮会自动解除.但是当"取消"按钮被触发时,我无法检测或接收任何回调.VC2是一个黑盒子.

视图控制器(称为VC1)将使用presentViewController:animated:completion:方法呈现VC2 .

当VC2被解雇时,VC1必须检测哪些选项?

编辑:从@rory mckinnel的评论和@NicolasMiari的回答,我尝试了以下内容:

在VC2中:

-(void)cancelButton:(id)sender
{
    [self dismissViewControllerAnimated:YES completion:^{

    }];
//    [super dismissViewControllerAnimated:YES completion:^{
//        
//    }];
}
Run Code Online (Sandbox Code Playgroud)

在VC1中:

//-(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
- (void)dismissViewControllerAnimated:(BOOL)flag
                           completion:(void (^ _Nullable)(void))completion
{
    NSLog(@"%s ", __PRETTY_FUNCTION__);
    [super dismissViewControllerAnimated:flag completion:completion];
//    [self dismissViewControllerAnimated:YES completion:^{
//        
//    }];
}
Run Code Online (Sandbox Code Playgroud)

dismissViewControllerAnimatedVC1中没有被调用.

Ror*_*nel 44

根据文档,呈现控制器负责实际解雇.当呈现的控制器解散时,它会要求演示者为此进行操作.因此,如果你在VC1控制器中覆盖dismissViewControllerAnimated,我相信当你在VC2上点击取消时它会被调用.检测解雇,然后调用将执行实际解雇的超类版本.

从讨论中发现,这似乎不起作用.而不是依靠的不是调用底层机制,dismissViewControllerAnimated:completion在VC2本身,叫dismissViewControllerAnimated:completionself.presentingViewController在VC2.然后,这将直接调用您的覆盖.

一个更好的方法是让VC2提供一个在模态控制器完成时调用的块.

所以在VC2中,提供一个带有名称的块属性onDoneBlock.

在VC1中,您提供如下:

  • 在VC1中,创建VC2

  • 将VC2的done处理程序设置为: VC2.onDoneBlock={[VC2 dismissViewControllerAnimated:YES completion:nil]};

  • 使用[self presentViewController:VC2 animated:YES completion:nil]正常呈现VC2控制器;

  • 在VC2中,在取消目标操作中调用 self.onDoneBlock();

结果是VC2告诉谁提出它已完成.你可以扩展onDoneBlock为有参数,表明模态是否被选中,取消,成功等....

  • 只是想感谢并欣赏它的工作原理……即使在 4 年后!谢谢! (2认同)

Sen*_*ian 32

您可以在要观察另一个呈现的视图控制器的解除的父视图控制器UIViewControllerTransitioningDelegate上使用:

anotherViewControllerYouWantToObserve.transitioningDelegate = self
Run Code Online (Sandbox Code Playgroud)

并观察解雇情况:

func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    print("anotherViewControllerYouWantToObserve was dismissed")
    return nil
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案!Objective C 版本 - -(id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{ NSLog(@"valueDateChangeEditScrn 被解雇"); 返回零;} (2认同)

bry*_*ejl 27

使用块属性

在VC2中声明

var onDoneBlock : ((Bool) -> Void)?
Run Code Online (Sandbox Code Playgroud)

在VC1中设置

VC2.onDoneBlock = { result in
                // Do something
            }
Run Code Online (Sandbox Code Playgroud)

当你即将解雇时,请在VC2中打电话

onDoneBlock!(true)
Run Code Online (Sandbox Code Playgroud)


Nic*_*ari 10

呈现呈现的视图控制器都可以调用dismissViewController:animated:以便关闭呈现的视图控制器.

前一个选项(可以说)是"正确的",设计明智的:相同的"父"视图控制器负责呈现和解除模态("子")视图控制器.

但是,后者更方便:通常,"dismiss"按钮附加到呈现的视图控制器的视图,并且它将所述视图控制器设置为其动作目标.

如果您采用前一种方法,则您已经知道呈现视图控制器中发生解雇的代码行:在紧接着之后dismissViewControllerAnimated:completion:或在完成块之内运行代码.

如果您采用后一种方法(呈现的视图控制器自行解除),请记住,dismissViewControllerAnimated:completion:从呈现的视图控制器调用会导致UIKit在呈现视图控制器上调用该方法:

讨论

呈现视图控制器负责解除它所呈现的视图控制器.如果在呈现的视图控制器本身上调用此方法,UIKit会要求呈现视图控制器处理解雇.

(来源:UIViewController类参考)

因此,为了拦截此类事件,您可以在呈现视图控制器中覆盖该方法:

override func dismiss(animated flag: Bool,
                         completion: (() -> Void)?) {
    super.dismiss(animated: flag, completion: completion)

    // Your custom code here...
}
Run Code Online (Sandbox Code Playgroud)

  • 当用户通过从顶部滑动关闭模态视图控制器时,不会调用它! (4认同)

Iva*_*van 9

extension Foo: UIAdaptivePresentationControllerDelegate {
    func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
        //call whatever you want
    }
}

vc.presentationController?.delegate = foo
Run Code Online (Sandbox Code Playgroud)

  • 仅限“iOS 13.0+” (2认同)

Jor*_*mar 8

有一个特殊的布尔属性里面UIViewControllerisBeingDismissed,你可以使用这个目的:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if isBeingDismissed {
        // TODO: Do your stuff here.
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在 iOS13 模态演示中,当用户开始拖动控制器来关闭时,这是真的,但他们可以选择不完成关闭。 (21认同)
  • 最简单的最佳答案,正确解决大多数问题并且不需要额外的实现。 (4认同)
  • 您可以在“viewDidDisappear”中使用“isBeingDismissed”来代替“viewWillDisappear”。override func viewDidDisappear(_animated: Bool) { super.viewDidDisappear(animated) if isBeingDismissed { print("DISSMISSED!") } } (4认同)
  • @Estel 我一直在说假话 (3认同)
  • `viewDidDisappear` 是更合适的方法 (2认同)
  • 另外,如果你的 UIViewController 是用 UINavigationController 包装的,那么你应该使用: navigationController?.isBeingDismissed ?? 正在被解雇` (2认同)

Sha*_*avi 6

按以下方式使用willMove(toParent: UIViewController?)似乎对我有用。(在iOS12上测试)。

override func willMove(toParent parent: UIViewController?) {
    super.willMove(toParent: parent);

    if parent == nil
    {
        // View controller is being removed.
        // Perform onDismiss action
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 仅当添加到容器 VC 或从容器 VC 中删除时才有效。 (2认同)

lan*_*loc 6

如果您有一个可以像页面一样通过滑动关闭的模态演示文稿,则此方法非常有效。

override func endAppearanceTransition() {
     if isBeingDismissed{
          print("dismissal logic here")
     }
     super.endAppearanceTransition()
 }
Run Code Online (Sandbox Code Playgroud)