检测表在 iOS 13 上被取消
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/56568967/
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
Detecting sheet was dismissed on iOS 13
提问by Marcos Tanaka
Before iOS 13, presented view controllers used to cover the entire screen. And, when dismissed, the parent view controller viewDidAppear
function were executed.
在 iOS 13 之前,呈现的视图控制器用于覆盖整个屏幕。并且,当被解雇时,父视图控制器viewDidAppear
函数被执行。
Now iOS 13 will present view controllers as a sheet as default, which means the card will partially cover the underlying view controller, which means that viewDidAppear
will not be called, because the parent view controller has never actually disappeared.
现在iOS 13默认将视图控制器呈现为一张表,这意味着卡片将部分覆盖底层视图控制器,这意味着viewDidAppear
不会被调用,因为父视图控制器从未真正消失过。
Is there a way to detect that the presented view controller sheet was dismissed? Some other function I can override in the parent view controller rather than using some sort of delegate?
有没有办法检测到呈现的视图控制器表被解除?我可以在父视图控制器中覆盖的其他一些功能而不是使用某种委托?
采纳答案by matt
Is there a way to detect that the presented view controller sheet was dismissed?
有没有办法检测到呈现的视图控制器表被解除?
Yes.
是的。
Some other function I can override in the parent view controller rather than using some sort of delegate?
我可以在父视图控制器中覆盖的其他一些功能而不是使用某种委托?
No. "Some sort of delegate" is how you do it. Make yourself the presentation controller's delegate and override presentationControllerDidDismiss(_:)
.
不。“某种委托”是你如何做的。使自己成为演示控制器的委托并覆盖presentationControllerDidDismiss(_:)
。
The lack of a general runtime-generated event informing you that a presented view controller, whether fullscreen or not, has been dismissed, is indeed troublesome; but it's not a new issue, because there have always been non-fullscreen presented view controllers. It's just that now (in iOS 13) there are more of them! I devote a separate question-and-answer to this topic elsewhere: Unified UIViewController "became frontmost" detection?.
缺少一个通用的运行时生成的事件来通知您所呈现的视图控制器(无论是否全屏)已被取消,这确实很麻烦;但这不是一个新问题,因为一直存在非全屏呈现的视图控制器。只是现在(在 iOS 13 中)有更多它们!我在别处专门针对此主题进行了单独的问答:Unified UIViewController “become frontmost” detection?.
回答by Matt
Here's a code example of a parent view-controller which is notified when the child view-controller it presents as a sheet(i.e., in the default iOS 13 manner) is dismissed:
这是父视图控制器的代码示例,当它作为工作表呈现的子视图控制器(即,以默认的 iOS 13 方式)被关闭时会收到通知:
public final class Parent: UIViewController, UIAdaptivePresentationControllerDelegate
{
// This is assuming that the segue is a storyboard segue;
// if you're manually presenting, just see the delegate there.
public override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "mySegue" {
segue.destination.presentationController?.delegate = self;
}
}
public func presentationControllerDidDismiss(
_ presentationController: UIPresentationController)
{
// Only called when the sheet is dismissed by DRAGGING.
// You'll need something extra if you call .dismiss() on the child.
// (I found that overriding dismiss in the child and calling
// presentationController.delegate?.presentationControllerDidDismiss
// works well).
}
}
Jerland2's answer is confused, since (a) the original questioner wanted to get a function call when the sheet is dismissed(whereas he implemented presentationControllerDidAttemptToDismiss, which is called when the user tries and failsto dismiss the sheet), and (b) setting isModalInPresentation is entirely orthogonal and in fact will make the presented sheet undismissable (which is the opposite of what OP wants).
Jerland2 的回答令人困惑,因为 (a) 原始提问者希望在关闭工作表时调用函数(而他实现了presentationControllerDidAttemptToDismiss,当用户尝试关闭工作表失败时调用),以及 (b) 设置 isModalInPresentation是完全正交的,实际上将使所呈现的工作表不可拒绝(这与 OP 想要的相反)。
回答by PiterPan
Another option to get back viewWillAppear
and viewDidAppear
is set
返回viewWillAppear
并viewDidAppear
设置的另一个选项
let vc = UIViewController()
vc.modalPresentationStyle = .fullScreen
this option cover full screen and after dismiss, calls above methods
此选项覆盖全屏,关闭后,调用上述方法
回答by Jerland2
For future readers here is a more complete answer with implementation:
对于未来的读者,这里有一个更完整的实现答案:
- In the root view controllers prepare for segue add the following (Assuming your modal has a nav controller)
- 在准备转场的根视图控制器中添加以下内容(假设您的模式有一个导航控制器)
// Modal Dismiss iOS 13
modalNavController.presentationController?.delegate = modalVc
- In the modal view controller add the following delegate + method
- 在模态视图控制器中添加以下委托 + 方法
// MARK: - iOS 13 Modal (Swipe to Dismiss)
extension ModalViewController: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
print("slide to dismiss stopped")
self.dismiss(animated: true, completion: nil)
}
}
- Ensure in the modal View Controller that the following property is true in order for the delegate method to be called
- 确保在模态视图控制器中以下属性为真,以便调用委托方法
self.isModalInPresentation = true
- Profit
- 利润
回答by coders
DRAG OR CALL DISMISS FUNC will work with below code.
DRAG OR CALL DISMISS FUNC 将使用以下代码。
1) In root view controller, you tell that which is its presentation view controller as below code
1)在根视图控制器中,你告诉哪个是它的呈现视图控制器,如下代码
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "presenterID" {
let navigationController = segue.destination as! UINavigationController
if #available(iOS 13.0, *) {
let controller = navigationController.topViewController as! presentationviewcontroller
// Modal Dismiss iOS 13
controller.presentationController?.delegate = self
} else {
// Fallback on earlier versions
}
navigationController.presentationController?.delegate = self
}
}
2) Again in the root view controller, you tell what you will do when its presentation view controller is dissmised
2) 再次在根视图控制器中,你告诉当它的呈现视图控制器被关闭时你会做什么
public func presentationControllerDidDismiss(
_ presentationController: UIPresentationController)
{
print("presentationControllerDidDismiss")
}
1) In the presentation view controller, When you hit cancel or save button in this picture. Below code will be called.The
1)在演示视图控制器中,当您点击此图片中的取消或保存按钮时。下面的代码将被调用。
self.dismiss(animated: true) {
self.presentationController?.delegate?.presentationControllerDidDismiss?(self.presentationController!)
}
回答by craft
Override viewWillDisappear on the UIViewController that's being dismissed. It will alert you to a dismissal via isBeingDismissed
boolean flag.
在被解散的 UIViewController 上覆盖 viewWillDisappear。它会通过isBeingDismissed
布尔标志提醒您解雇。
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isBeingDismissed {
print("user is dismissing the vc")
}
}
** If the user is halfway through the swipe down and swipes the card back up, it'll still register as being dismissed, even if the card is not dismissed. But that's an edge case you may not care about.
** 如果用户在向下滑动中途并再次向上滑动卡片,它仍会注册为已关闭,即使卡片没有被关闭。但这是一个你可能不关心的边缘情况。
回答by dimo hamdy
Swift
迅速
General Solution to callviewWillAppear
in iOS13
viewWillAppear
在iOS13 中调用的一般解决方案
class ViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear")
}
//Show new viewController
@IBAction func show(_ sender: Any) {
let newViewController = NewViewController()
//set delegate of UIAdaptivePresentationControllerDelegate to self
newViewController.presentationController?.delegate = self
present(newViewController, animated: true, completion: nil)
}
}
extension UIViewController: UIAdaptivePresentationControllerDelegate {
public func presentationControllerDidDismiss( _ presentationController: UIPresentationController) {
if #available(iOS 13, *) {
//Call viewWillAppear only in iOS 13
viewWillAppear(true)
}
}
}
回答by Abelardo del angel Quiroz
If you used the ModalPresentationStyle in FullScreen, the behavior of the controller is back as usual.
如果您在 FullScreen 中使用 ModalPresentationStyle,则控制器的行为会恢复正常。
ConsultarController controllerConsultar = this.Storyboard.InstantiateViewController("ConsultarController") as ConsultarController; controllerConsultar.ModalPresentationStyle = UIModalPresentationStyle.FullScreen; this.NavigationController.PushViewController(controllerConsultar, true);
ConsultarController controllerConsultar = this.Storyboard.InstantiateViewController("ConsultarController") as ConsultarController; controllerConsultar.ModalPresentationStyle = UIModalPresentationStyle.FullScreen; this.NavigationController.PushViewController(controllerConsultar, true);
回答by jacob
From my point of view, Apple should not set pageSheet
is the default modalPresentationStyle
在我看来,Apple 不应该设置pageSheet
为默认值modalPresentationStyle
I'd like to bring fullScreen
style back to default by using swizzling
我想fullScreen
通过使用将样式恢复为默认值swizzling
Like this:
像这样:
private func _swizzling(forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector) {
if let originalMethod = class_getInstanceMethod(forClass, originalSelector),
let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector) {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
extension UIViewController {
static func preventPageSheetPresentationStyle () {
UIViewController.preventPageSheetPresentation
}
static let preventPageSheetPresentation: Void = {
if #available(iOS 13, *) {
_swizzling(forClass: UIViewController.self,
originalSelector: #selector(present(_: animated: completion:)),
swizzledSelector: #selector(_swizzledPresent(_: animated: completion:)))
}
}()
@available(iOS 13.0, *)
private func _swizzledPresent(_ viewControllerToPresent: UIViewController,
animated flag: Bool,
completion: (() -> Void)? = nil) {
if viewControllerToPresent.modalPresentationStyle == .pageSheet
|| viewControllerToPresent.modalPresentationStyle == .automatic {
viewControllerToPresent.modalPresentationStyle = .fullScreen
}
_swizzledPresent(viewControllerToPresent, animated: flag, completion: completion)
}
}
And then put this line to your AppDelegate
然后把这条线放到你的 AppDelegate
UIViewController.preventPageSheetPresentationStyle()
回答by Mikesch8764
wouldn't it be simple to call the presentingViewController.viewWillAppear? befor dismissing?
调用presentingViewController.viewWillAppear 不是很简单吗?解雇前?
self.presentingViewController?.viewWillAppear(false)
self.dismiss(animated: true, completion: nil)