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
Completion Handler for Uinavigationcontroller "Pushviewcontroller:Animated"
Notificationcenter Issue on Swift 3
How to Draw Border Around a Uilabel
Xcode 8/Swift 3: "Expression of Type Uiviewcontroller? Is Unused" Warning
Storyboards VS. the Old Xib Way
Using Existing System Sounds in iOS App [Swift|
How to Implement a Swiping/Sliding Animation Between Views
Open Link to Facebook Page from iOS App
Coredata Get Distinct Values of Attribute
Format Uilabel with Bullet Points
Storing Authentication Tokens on iOS - Nsuserdefaults VS Keychain
Scale Image in an Uibutton to Aspectfit
Swift: How to Get Substring from Start to Last Index of Character
How to Use Sfsafariviewcontroller with Swiftui
Why Is Uiscrollview Leaving Space on Top and Does Not Scroll to the Bottom