ios 检测何时关闭呈现的视图控制器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32853212/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detect when a presented view controller is dismissed
提问by user523234
Let's say, I have an instance of a view controller class called VC2. In VC2, there is a "cancel" button that will dismiss itself. But I can't detect or receive any callback when the "cancel" button got trigger. VC2 is a black box.
假设,我有一个名为 VC2 的视图控制器类的实例。在 VC2 中,有一个“取消”按钮可以自行关闭。但是当“取消”按钮被触发时,我无法检测或接收任何回调。VC2 是一个黑匣子。
A view controller (called VC1) will present VC2 using presentViewController:animated:completion:
method.
视图控制器(称为 VC1)将使用presentViewController:animated:completion:
方法呈现 VC2 。
What options does VC1 have to detect when VC2 was dismissed?
当 VC2 被解雇时,VC1 必须检测哪些选项?
Edit: From the comment of @rory mckinnel and answer of @NicolasMiari, I tried the following:
编辑:根据@rory mckinnel 的评论和@NicolasMiari 的回答,我尝试了以下操作:
In VC2:
在 VC2 中:
-(void)cancelButton:(id)sender
{
[self dismissViewControllerAnimated:YES completion:^{
}];
// [super dismissViewControllerAnimated:YES completion:^{
//
// }];
}
In VC1:
在 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:^{
//
// }];
}
But the dismissViewControllerAnimated
in the VC1 was not getting called.
但是dismissViewControllerAnimated
VC1 中的 没有被调用。
采纳答案by Rory McKinnel
According to the docs, the presenting controller is responsible for the actual dismiss. When the presented controller dismisses itself, it will ask the presenter to do it for it. So if you override dismissViewControllerAnimated in your VC1 controller I believe it will get called when you hit cancel on VC2. Detect the dismiss and then call the super classes version which will do the actual dismiss.
根据文档,呈现控制器负责实际解雇。当被呈现的控制器解散自己时,它会要求呈现者为它做这件事。因此,如果您在 VC1 控制器中覆盖了dismissViewControllerAnimated,我相信当您在 VC2 上点击取消时它会被调用。检测解雇,然后调用将执行实际解雇的超类版本。
As found from discussion this does not seem to work. Rather than rely on the underlying mechanism, instead of calling dismissViewControllerAnimated:completion
on VC2 itself, call dismissViewControllerAnimated:completion
on self.presentingViewController
in VC2. This will then call your override directly.
从讨论中发现这似乎不起作用。与其依赖底层机制,不如dismissViewControllerAnimated:completion
在VC2本身上调用dismissViewControllerAnimated:completion
,self.presentingViewController
在VC2中调用。这将直接调用您的覆盖。
A better approach altogether would be to have VC2 provide a block which is called when the modal controller has completed.
更好的方法是让 VC2 提供一个在模态控制器完成时调用的块。
So in VC2, provide a block property say with the name onDoneBlock
.
所以在 VC2 中,提供一个名为 的块属性onDoneBlock
。
In VC1 you present as follows:
在 VC1 中,您显示如下:
In VC1, create VC2
Set the done handler for VC2 as:
VC2.onDoneBlock={[VC2 dismissViewControllerAnimated:YES completion:nil]};
Present the VC2 controller as normal using [self presentViewController:VC2 animated:YES completion:nil];
In VC2, in the cancel target action call
self.onDoneBlock();
在VC1中,创建VC2
将 VC2 的 done 处理程序设置为:
VC2.onDoneBlock={[VC2 dismissViewControllerAnimated:YES completion:nil]};
使用 [self presentViewController:VC2 animation:YES completion:nil] 正常显示 VC2 控制器;
在VC2中,在取消目标动作调用中
self.onDoneBlock();
The result is VC2 tells whoever raises it that it is done. You can extend the onDoneBlock
to have arguments which indicate if the modal comleted, cancelled, succeeded etc....
结果是 VC2 告诉任何提出它的人它已经完成。您可以将 扩展onDoneBlock
为具有指示模态是否完成、取消、成功等的参数......
回答by brycejl
Use a Block Property
使用块属性
Declare in VC2
在 VC2 中声明
var onDoneBlock : ((Bool) -> Void)?
Setup in VC1
在 VC1 中设置
VC2.onDoneBlock = { result in
// Do something
}
Call in VC2 when you're about to dismiss
当您要解雇时调用 VC2
onDoneBlock!(true)
回答by Joris Weimar
There is a special Boolean property inside UIViewController
called isBeingDismissed
that you can use for this purpose:
有一个特殊的布尔属性里面UIViewController
叫isBeingDismissed
,你可以使用这个目的:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isBeingDismissed {
// TODO: Do your stuff here.
}
}
回答by Nicolas Miari
Both the presenting andpresented view controller can call dismissViewController:animated:
in order to dismiss the presented view controller.
呈现和呈现的视图控制器都可以调用dismissViewController:animated:
以关闭呈现的视图控制器。
The former option is (arguably) the "correct" one, design-wise: The same "parent" view controller is responsible for both presenting and dismissing the modal ("child") view controller.
前一个选项(可以说)是“正确”的设计方式:同一个“父”视图控制器负责呈现和关闭模态(“子”)视图控制器。
However, the latter is more convenient: typically, the "dismiss" button is attached to the presented view controller's view, and it has said view controller set as its action target.
然而,后者更方便:通常,“关闭”按钮附加到呈现的视图控制器的视图,并且将所述视图控制器设置为其动作目标。
If you are adopting the former approach, you already know the line of code in your presenting view controller where the dismissal occurs: either run your code just after dismissViewControllerAnimated:completion:
, or within the completion block.
如果您采用前一种方法,您已经知道呈现视图控制器中发生解雇的代码行:要么在 之后运行您的代码dismissViewControllerAnimated:completion:
,要么在完成块内运行。
If you are adopting the latter approach (presented view controller dismisses itself), keep in mind that calling dismissViewControllerAnimated:completion:
from the presented view controller causes UIKit to in turn call that method on the presenting view controller:
如果您采用后一种方法(呈现的视图控制器自行解除),请记住,dismissViewControllerAnimated:completion:
从呈现的视图控制器调用会导致 UIKit 依次在呈现的视图控制器上调用该方法:
Discussion
The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, UIKit asks the presenting view controller to handle the dismissal.
讨论
呈现视图控制器负责解除它呈现的视图控制器。如果您在呈现的视图控制器本身上调用此方法,UIKit 会要求呈现的视图控制器处理关闭。
(source: UIViewController Class Reference)
So, in order to intercept such event, you could override that method in the presentingview controller:
因此,为了拦截此类事件,您可以在呈现视图控制器中覆盖该方法:
override func dismiss(animated flag: Bool,
completion: (() -> Void)?) {
super.dismiss(animated: flag, completion: completion)
// Your custom code here...
}
回答by fruitcoder
I use the following to signal to a coordinator that the view controller is "done". This is used in a AVPlayerViewController
subclass in a tvOS application and will be called after the playerVC dismissal transition has completed:
我使用以下命令向协调器发出视图控制器已“完成”的信号。这AVPlayerViewController
在 tvOS 应用程序的子类中使用,将在 playerVC 解除转换完成后调用:
class PlayerViewController: AVPlayerViewController {
var onDismissal: (() -> Void)?
override func beginAppearanceTransition(_ isAppearing: Bool, animated: Bool) {
super.beginAppearanceTransition(isAppearing, animated: animated)
transitionCoordinator?.animate(alongsideTransition: nil,
completion: { [weak self] _ in
if !isAppearing {
self?.onDismissal?()
}
})
}
}
回答by valarMorghulis
You can use unwind segue to do this task, no need to use the dismissModalViewController. Define an unwind segue method in your VC1.
你可以使用 unwind segue 来完成这个任务,不需要使用dismissModalViewController。在 VC1 中定义一个 unwind segue 方法。
See this link on how to create the unwind segue, https://stackoverflow.com/a/15839298/5647055.
请参阅有关如何创建展开转场的链接,https://stackoverflow.com/a/15839298/5647055 。
Assuming your unwind segue is set up, in the action method defined for your "Cancel" button, you can perform the segue as -
假设您的 unwind segue 已设置,在为“取消”按钮定义的操作方法中,您可以将 segue 执行为 -
[self performSegueWithIdentifier:@"YourUnwindSegueName" sender:nil];
Now, whenever you press the "Cancel" button in the VC2, it will be dismissed and VC1 will appear. It will also call the unwind method, you defined in VC1. Now, you know when the presented view controller is dismissed.
现在,只要您按下 VC2 中的“取消”按钮,它就会被解除,而 VC1 就会出现。它还将调用您在 VC1 中定义的 unwind 方法。现在,您知道显示的视图控制器何时被解除。
回答by Andrew Coad
@user523234 - "But the dismissViewControllerAnimated in the VC1 was not getting called."
@ user523234 - “但是 VC1 中的dismissViewControllerAnimated 没有被调用。”
You can't assume that VC1 actually does the presenting - it could be the root view controller, VC0, say. There are 3 view controllers involved:
您不能假设 VC1 确实进行了呈现——比如说,它可能是根视图控制器 VC0。涉及 3 个视图控制器:
- sourceViewController
- presentingViewController
- presentedViewController
- 源视图控制器
- 呈现视图控制器
- 呈现的视图控制器
In your example, VC1 = sourceViewController
, VC2 = presentedViewController
, ?? = presentingViewController
- maybe VC1, maybe not.
在您的示例中,VC1 = sourceViewController
, VC2 = presentedViewController
, ?? = presentingViewController
- 也许是 VC1,也许不是。
However, you can always rely on VC1.animationControllerForDismissedController being called (if you have implemented the delegate methods) when dismissing VC2 and in that method you can do what you want with VC1
但是,在解除 VC2 时,您始终可以依赖于 VC1.animationControllerForDismissedController 被调用(如果您已经实现了委托方法),并且在该方法中您可以使用 VC1 执行您想要的操作
回答by Izhido
I've seen this post so many times when dealing with this issue, I thought I might finally shed some light on a possible answer.
在处理这个问题时,我已经多次看到这篇文章,我想我可能最终会阐明可能的答案。
If what you need is to know whether user-initiated actions (like gestures on screen) engaged dismissal for an UIActionController, and don't want to invest time in creating subclasses or extensions or whatever in your code, there is an alternative.
如果您需要知道用户启动的操作(如屏幕上的手势)是否会关闭 UIActionController,并且不想花时间在您的代码中创建子类或扩展或任何内容,那么还有一种替代方法。
As it turns out, the popoverPresentationControllerproperty of an UIActionController(or, rather, any UIViewController to that effect), has a delegateyou can set anytime in your code, which is of type UIPopoverPresentationControllerDelegate, and has the following methods:
事实证明,UIActionController(或者,任何具有该效果的 UIViewController)的popoverPresentationController属性具有您可以随时在代码中设置的委托,其类型为UIPopoverPresentationControllerDelegate,并具有以下方法:
Assign the delegate from your action controller, implement your method(s) of choice in the delegate class (view, view controller or whatever), and voila!
从您的动作控制器分配委托,在委托类(视图、视图控制器或其他)中实现您选择的方法,瞧!
Hope this helps.
希望这可以帮助。
回答by Shavi
Using the willMove(toParent: UIViewController?)
in the following way seemed to work for me. (Tested on iOS12).
以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
}
}
回答by Tapansinh Solanki
- Create one class file (.h/.m) and name it : DismissSegue
Select Subclass of : UIStoryboardSegue
Go to DismissSegue.m file & write down following code:
- (void)perform { UIViewController *sourceViewController = self.sourceViewController; [sourceViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; }
Open storyboard & then Ctrl+drag from cancel button to VC1 & select Action Segue as Dismiss and you are done.
- 创建一个类文件 (.h/.m) 并将其命名为:DismissSegue
选择子类:UIStoryboardSegue
转到 DismissSegue.m 文件并写下以下代码:
- (void)perform { UIViewController *sourceViewController = self.sourceViewController; [sourceViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; }
打开故事板,然后按住 Ctrl 键并从取消按钮拖动到 VC1 并选择 Action Segue 为 Dismiss,您就完成了。