假设我有一个名为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:^{
//
// }];
}
在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:^{
//
// }];
}
但是VC1中的dismissViewControllerAnimated
没有被调用。
答案 0 :(得分:35)
根据文件,提交控制人负责实际解雇。当呈现的控制器解散时,它会要求演示者为此进行操作。因此,如果你在VC1控制器中覆盖dismissViewControllerAnimated,我相信当你在VC2上点击取消时它会被调用。检测解雇,然后调用将执行实际解雇的超类版本。
从讨论中发现,这似乎不起作用。而不是依赖于底层机制,而不是在VC2本身上调用dismissViewControllerAnimated:completion
,而是在VC2中的dismissViewControllerAnimated:completion
上调用self.presentingViewController
。然后,这将直接调用您的覆盖。
一个更好的方法是让VC2提供一个在模态控制器完成时调用的块。
所以在VC2中,提供一个名为onDoneBlock
的块属性。
在VC1中,您显示如下:
在VC1中,创建VC2
将VC2的done处理程序设置为:VC2.onDoneBlock={[VC2 dismissViewControllerAnimated:YES completion:nil]};
使用[self presentViewController:VC2 animated:YES completion:nil];
在VC2中,取消目标操作调用self.onDoneBlock();
结果是VC2告诉任何人提出它已完成。您可以扩展onDoneBlock
以包含指示模式是否已被注释,取消,成功等的参数....
答案 1 :(得分:20)
使用区块属性
在VC2中声明
var onDoneBlock : ((Bool) -> Void)?
在VC1中设置
VC2.onDoneBlock = { result in
// Do something
}
当您即将解雇
时,请在VC2中拨打电话onDoneBlock!(true)
答案 2 :(得分:9)
呈现和呈现的视图控制器都可以调用dismissViewController:animated:
以解除显示的视图控制器。
前一种选择(可以说是)"正确的"一,设计明智:相同的父母"视图控制器负责显示和解除模态("子")视图控制器。
然而,后者更方便:通常,"解雇"按钮附加到呈现的视图控制器的视图中,并且它将所述视图控制器设置为其操作目标。
如果您采用前一种方法,您已经知道呈现视图控制器中发生解雇的代码行:在dismissViewControllerAnimated:completion:
之后运行代码,或者在完成块之内运行代码。
如果您采用后一种方法(呈现的视图控制器自行解除),请记住,从呈现的视图控制器调用dismissViewControllerAnimated:completion:
会导致UIKit在呈现视图控制器上调用该方法:
<强>讨论强>
呈现视图控制器负责 解雇它提出的视图控制器。如果你调用这个方法 在呈现的视图控制器本身,UIKit要求呈现 查看控制人处理解雇。
(source: UIViewController Class Reference)
因此,为了拦截此类事件,您可以在呈现视图控制器中覆盖该方法:
override func dismissViewControllerAnimated(_ flag: Bool,
completion completion: (() -> Void)?)
{
super.dismissViewControllerAnimated(flag, completion:completion)
// Your custom code here...
}
答案 3 :(得分:3)
extension Foo: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
//call whatever you want
}
}
vc.presentationController?.delegate = foo
答案 4 :(得分:2)
您可以使用unwind segue执行此任务,无需使用dismissModalViewController。在VC1中定义一个展开segue方法。
请参阅此链接,了解如何创建展开segue,https://stackoverflow.com/a/15839298/5647055。
假设您的展开segue已设置,在为“取消”按钮定义的操作方法中,您可以执行segue as -
[self performSegueWithIdentifier:@"YourUnwindSegueName" sender:nil];
现在,无论何时按下VC2中的“取消”按钮,它都会被解除,VC1将会出现。它还将调用您在VC1中定义的unwind方法。现在,您知道所呈现的视图控制器何时被解除。
答案 5 :(得分:2)
我使用以下内容向协调器发出信号,告知视图控制器已完成&#34;。这在tvOS应用程序的AVPlayerViewController
子类中使用,并将在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?()
}
})
}
}
答案 6 :(得分:1)
@ user523234 - “但VC1中的dismissViewControllerAnimated没有被调用。”
你不能假设VC1实际上进行了呈现 - 它可能是根视图控制器,VC0。涉及3个视图控制器:
- sourceViewController
- presentingViewController
- presentedViewController
在您的示例中,request_id
,VC1 = sourceViewController
,VC2 = presentedViewController
- 可能是VC1,也许不是。
但是,在解除VC2时,你总是可以依赖VC1.animationControllerForDismissedController(如果你已经实现了委托方法),在那个方法中你可以用VC1做你想做的事
答案 7 :(得分:1)
更高效的方法是创建一个用于呈现控制器的协议,然后调用 childControllers
protocol DismissListener {
func childControllerWillDismiss(_ controller : UIViewController, animated : Bool)
func childControllerDidDismiss(_ controller : UIViewController, animated : Bool)
}
extension UIViewController {
func dismissWithListener(animated flag: Bool, completion: (() -> Void)? = nil){
self.viewWillDismiss(flag)
self.dismiss(animated: flag, completion: {
completion?()
self.viewDidDismiss(true)
})
}
func viewWillDismiss(_ animate : Bool) {
(presentingViewController as? DismissListener)?.childControllerWillDismiss(self, animated: animate)
}
func viewDidDismiss(_ animate : Bool) {
(presentingViewController as? DismissListener)?.childControllerDidDismiss(self, animated: animate)
}
}
然后当视图即将关闭时:
self.dismissWithListener(animated: true, completion: nil)
最后只需将协议添加到您希望收听的任何视图控制器!
class ViewController: UIViewController, DismissListener {
func childControllerWillDismiss(_ controller: UIViewController, animated: Bool) {
}
func childControllerDidDismiss(_ controller: UIViewController, animated: Bool) {
}
}
答案 8 :(得分:1)
按以下方式使用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
}
}
答案 9 :(得分:1)
另一种选择是监听自定义UIPresentationController的dismissalTransitionDidEnd()
答案 10 :(得分:0)
如果您有一个模态演示文稿,它可以像页面一样通过滑动来消除,这很有效。
override func endAppearanceTransition() {
if isBeingDismissed{
print("dismissal logic here")
}
}
答案 11 :(得分:0)
选择子类:UIStoryboardSegue
转到DismissSegue.m文件&amp;记下以下代码:
//LOGIN FORM
app.get('/login', function (req, res) {
res.render('../views/signup-signin/login');
});
//LOGIN POST
app.post('/login', function (req, res) {
User.find(req.body.username, function (user) {
bcrypt.compare(req.body.password, user.password, function (err, result) {
if (result) {
req.session.currentUser = user.id;
res.redirect('/');
} else {
res.redirect('/login');
}
});
});
});
//LOGOUT
app.delete('/logout', function (req, res) {
req.session.currentUser = null;
res.redirect('/');
});
打开故事板&amp;然后按Ctrl +从取消按钮拖动到VC1&amp;选择Action Segue作为Dismiss,你就完成了。
答案 12 :(得分:0)
您可以在父视图控制器上使用 UIAdaptivePresentationControllerDelegate
来观察另一个呈现的视图控制器的解除:
anotherViewControllerYouWantToObserve.transitioningDelegate = self
并观察解雇:
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
print("anotherViewControllerYouWantToObserve was dismissed")
return nil
}
答案 13 :(得分:0)
我没有看到似乎是一个简单的答案。如果这是重复,请原谅我...
由于 VC1 负责解雇 VC2,因此您需要在某个时候调用 vc1.dismiss()。所以你可以在 VC1 中覆盖dismiss() 并将你的操作代码放在那里:
class VC1 : UIViewController {
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
super.dismiss(animated: flag, completion: completion)
// PLACE YOUR ACTION CODE HERE
}
}
编辑: 您可能希望在关闭完成时触发您的代码,而不是在它开始时。所以在这种情况下,你应该使用:
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
super.dismiss(animated: flag) {
if let unwrapCompletion = completion { unwrapCompletion() }
// PLACE YOUR ACTION HERE
}
}
答案 14 :(得分:0)
我已将 deinit 用于ViewController
deinit {
dataSource.stopUpdates()
}
在取消分配类实例之前立即调用反初始化器。
答案 15 :(得分:0)
如果要处理视图控制器关闭,应使用以下代码。
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.isBeingDismissed && self.completion != NULL) {
self.completion();
}
}
很遗憾,我们无法在覆盖的方法(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^ _Nullable)(void))completion;
中调用完成,因为只有在调用此视图控制器的dismiss方法时,才会调用此方法。
答案 16 :(得分:0)
在处理此问题时,我已经看过很多次了,我想我可能最终会为可能的答案提供一些启示。
如果您需要了解用户发起的操作(例如屏幕上的手势)是否因UIActionController而被解雇,并且不想花时间在创建子类或扩展或代码中的任何内容上,还有一种选择。
事实证明,popoverPresentationController(或相应的任何UIViewController)的UIActionController属性具有一个delegate,您可以随时在代码中进行设置,类型为UIPopoverPresentationControllerDelegate,并具有以下方法:
从您的动作控制器中分配委托,在委托类(视图,视图控制器等)中实现您选择的方法,然后瞧瞧!
希望这会有所帮助。
答案 17 :(得分:0)
如上所述,解决方案是使用override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil)
。
对于那些想知道为什么override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil)
似乎并不总是有效的人,您可能会发现,如果该呼叫受到管理,则会被UINavigationController
截获。我写了一个子类,应该可以帮助您:
class DismissingNavigationController: UINavigationController {
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
super.dismiss(animated: flag, completion: completion)
topViewController?.dismiss(animated: flag, completion: completion)
}
}
答案 18 :(得分:0)
在显示的视图控制器中覆盖def callback(data):
# do stuff
cv2.imshow(winname, mat)
cv2.waitKey(delay)
rospy.subscribe(name, data_class, callback=callback)
rospy.spin()
函数。
viewWillDisappear
答案 19 :(得分:0)
override
viewDidAppear
为我做了诀窍。我在我的模态中使用了Singleton,现在我可以在调用VC,模态和其他任何地方设置和获取它。
答案 20 :(得分:0)
您可以使用Unwind Segues处理关闭uiviewcontroller。
https://developer.apple.com/library/content/technotes/tn2298/_index.html
https://spin.atomicobject.com/2014/12/01/program-ios-unwind-segue/
答案 21 :(得分:-1)
如果在视图控制器上覆盖被覆盖:
override func removeFromParentViewController() {
super.removeFromParentViewController()
// your code here
}
至少这对我有用。