catch on swipe to dismiss event
DeleteIntent:
DeleteIntent is a PendingIntent object that can be associated with a notification and gets fired when the notification gets deleted, ether by :
- User specific action
- User Delete all the notifications.
You can set the Pending Intent to a broadcast Receiver and then perform any action you want.
Intent intent = new Intent(this, MyBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, intent, 0);
Builder builder = new Notification.Builder(this):
..... code for your notification
builder.setDeleteIntent(pendingIntent);
MyBroadcastReceiver
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
.... code to handle cancel
}
}
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 if imagePickerController is closed with swipe down gesture with Objective C
First of all, you should not override viewDidDisappear:
in an extension in Swift (nor in a category in Objective-C). The result of overriding something in an extension/category is undefined behavior - it may work, it may not. It should never be relied upon.
Instead, assign the delegate of your image picker's presentationController
to some class, then have that class implement the presentationControllerDidDismiss:
method. This method is called when the user has taken action to dismiss the image picker successfully, after all animations are finished. (And note that it's not called if the image picker is dismissed programatically.)
Here's a short example that covers all the cases of dismissing your image picker without the need to override viewDidDisappear:
in an extension or category:
@interface ViewController() <UIAdaptivePresentationControllerDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@end
@implementation ViewController
- (IBAction)showImagePicker {
UIImagePickerController *imagePicker = [UIImagePickerController new];
imagePicker.delegate = self;
imagePicker.presentationController.delegate = self;
[self presentViewController:imagePicker animated:YES completion:nil];
}
#pragma mark - UIAdaptivePresentationControllerDelegate
- (void)presentationControllerWillDismiss:(UIPresentationController *)presentationController {
NSLog(@"The user began to swipe down to dismiss.");
}
- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController {
NSLog(@"The dismissal animation finished after the user swiped down.");
// This is probably where you want to put your code that you want to call.
}
#pragma mark - UIImagePickerControllerDelegate, UINavigationControllerDelegate
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
NSLog(@"The user tapped the image picker's Cancel button.");
[self dismissViewControllerAnimated:YES completion:^{
NSLog(@"The dismissal animation finished after the user tapped Cancel.");
}];
}
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey, id> *)info {
NSLog(@"The user selected an image from the image picker.");
[self dismissViewControllerAnimated:YES completion:^{
NSLog(@"The dismissal animation finished after the user selected an image.");
}];
}
@end
And here's a Swift version for good measure:
class ViewController: UIViewController {
@IBAction func showImagePicker() {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.presentationController?.delegate = self
present(imagePicker, animated: true)
}
}
extension ViewController: UIAdaptivePresentationControllerDelegate {
func presentationControllerWillDismiss(_ presentationController: UIPresentationController) {
print("The user began to swipe down to dismiss.")
}
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
print("The dismissal animation finished after the user swiped down.")
// This is probably where you want to put your code that you want to call.
}
}
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
print("The user tapped the image picker's Cancel button.")
dismiss(animated: true) {
print("The dismissal animation finished after the user tapped Cancel.")
}
}
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
print("The user selected an image from the image picker.")
dismiss(animated: true){
print("The dismissal animation finished after the user selected an image.")
}
}
}
Detect when a SwiftUI sheet is swiped away
onDismiss
is enough, you need just to add another variable and check on it.
For example:
let's declare an enum
enum SheetAction {
case cancel
case nothing
}
Then in your Main View:
@State var sheetAction: SheetAction = SheetAction.nothing
Like that the default action
which cause the dismiss will be nothing
which means a swipe down, not a button.
And pass it to your SheetView
.sheet(isPresented: self.$sheetActive, onDismiss: {
if sheetAction == .cancel {
// dismissed using cancel button
dismissTxt = "Cancel"
}else if sheetAction == .nothing {
// dismissed by swipe down
dismissTxt = "Swipe down"
}
}, content: {
SheetView(isActive: self.$sheetActive, action: self.$sheetAction)
})
When the user click on Cancel
button, change its value.
And don't miss to change the value to nothing
each time the SheetView
appears.
The final code:
enum SheetAction {
case cancel
case nothing
}
struct CustomView: View {
@State var sheetActive = false
@State var sheetAction: SheetAction = SheetAction.nothing
@State var dismissTxt = ""
var body: some View {
VStack {
Text(dismissTxt).foregroundColor(.gray)
Button(action: {
self.sheetActive = true
}, label: {
Text("Button")
})
}.sheet(isPresented: self.$sheetActive, onDismiss: {
if sheetAction == .cancel {
// dismissed using cancel button
dismissTxt = "Cancel"
}else if sheetAction == .nothing {
// dismissed by swipe down
dismissTxt = "Swipe down"
}
}, content: {
SheetView(isActive: self.$sheetActive, action: self.$sheetAction)
})
}
}
struct SheetView: View {
@Binding var isActive: Bool
@Binding var action: SheetAction
var body: some View {
NavigationView {
VStack {
Text("Sheet content")
}
.navigationBarItems(leading: Button(action: {
// Code that dismisses sheet
self.action = .cancel
self.isActive = false
}) {
Text("Cancel")
}, trailing: Button(action: {
// Code that adds something to something
}) {
Text("Add").bold()
})
}.onAppear {
action = .nothing
}
}
}
How to get notified when a presented view controller is dismissed with a gesture?
From iOS 13 Apple has introduced a new way for the users to dismiss
the presented view controller by pulling it down from the top. This event can be captured by implementing the UIAdaptivePresentationControllerDelegate
to the UIViewController
you're presenting on, in this case, the Presenting
controller. And then you can get notified about this event in the method presentationControllerDidDismiss
. Here is the code example :-
class Presenting: UIViewController, UIAdaptivePresentationControllerDelegate {
func someAction() {
let presented = Presented()
presented.presentationController?.delegate = self
present(presented, animated: true, completion: nil)
}
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).
}
}
Note:
- This method only gets triggered for dismissing by swiping from the top and not for the programmatic
dismiss(animated:,completion:)
method. - You don't need any custom delegate or
Notification
observer for getting the event where the user dismisses the controller by swiping down, so you can remove them.
Related Topics
Open Soft Keyboard Programmatically
How to Get Name of Wifi-Network Out of Android Using Android API
Cancel Notification on Remove Application from Multitask Panel
Set Selected Item in Android Bottomnavigationview
Notificationcompat with API 26
Error Message:This Android Sdk Requires Android Developer Toolkit Version 22.6.1 or Above
Run Code When Android App Is Closed/Sent to Background
Flutter Projects & Android X Migration Issues
Android: Retrieve Contact Name from Phone Number
Appcompatactivity.Oncreate Can Only Be Called from Within the Same Library Group
How to Exclude Certain Messages by Tag Name Using Android Adb Logcat
Adding Ripple Effect to Recyclerview Item
Android - How to Make a Button Flash
How to Perform an SQLite Query Within an Android Application
Versioncode VS Versionname in Android Manifest
How to Loop Through Dynamic JSON String Recursively in Android