Is There a Swiftui Equivalent for Viewwilldisappear(_:) or Detect When a View Is About to Be Removed

Is there a SwiftUI equivalent for viewWillDisappear(_:) or detect when a view is about to be removed?

Here is approach that works for me, it is not pure-SwiftUI but I assume worth posting

Usage:

   SomeView()
.onDisappear {
print("x Default disappear")
}
.onWillDisappear { // << order does NOT matter
print(">>> going to disappear")
}

Code:

struct WillDisappearHandler: UIViewControllerRepresentable {
func makeCoordinator() -> WillDisappearHandler.Coordinator {
Coordinator(onWillDisappear: onWillDisappear)
}

let onWillDisappear: () -> Void

func makeUIViewController(context: UIViewControllerRepresentableContext<WillDisappearHandler>) -> UIViewController {
context.coordinator
}

func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<WillDisappearHandler>) {
}

typealias UIViewControllerType = UIViewController

class Coordinator: UIViewController {
let onWillDisappear: () -> Void

init(onWillDisappear: @escaping () -> Void) {
self.onWillDisappear = onWillDisappear
super.init(nibName: nil, bundle: nil)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
onWillDisappear()
}
}
}

struct WillDisappearModifier: ViewModifier {
let callback: () -> Void

func body(content: Content) -> some View {
content
.background(WillDisappearHandler(onWillDisappear: callback))
}
}

extension View {
func onWillDisappear(_ perform: @escaping () -> Void) -> some View {
self.modifier(WillDisappearModifier(callback: perform))
}
}

Detecting sheet was dismissed on iOS 13

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(_:).

https://developer.apple.com/documentation/uikit/uiadaptivepresentationcontrollerdelegate/3229889-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?.

Detect when a presented view controller is dismissed

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.

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.

A better approach altogether would be to have VC2 provide a block which is called when the modal controller has completed.

So in VC2, provide a block property say with the name onDoneBlock.

In VC1 you present as follows:

  • 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();

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....

SwiftUI onDismiss not firing when presenting a sheet (Xcode Beta 5)

Your code looks fine to me. onDismiss is called when you use the swipe gesture to dismiss the modal view (as you would expect), but it isn't called when you use self.presentationMode.value.dismiss() to dismiss the modal view, which just seems like a bug to me. I don't see any reason why your code shouldn't work.

A workaround in the meantime could be to pass an onDismiss closure to your ModalView, and then call it after calling self.presentationMode.value.dismiss().



Related Topics



Leave a reply



Submit