Catch on Swipe to Dismiss Event

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

enter image description here

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:

  1. This method only gets triggered for dismissing by swiping from the top and not for the programmatic dismiss(animated:,completion:) method.
  2. 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



Leave a reply



Submit