Dismiss SVProgressHUD with Tap Gesture

I need to add a UITapGestureRecognizer to the SVProgressHUD. The SVProgressHUD already has the ability to dismiss using -(void) dismiss;. The code for this will dismiss the animation based on seconds.

- (void)dismiss {
for (UIGestureRecognizer *gesture in [[[self class] sharedView] gestureRecognizers]) {
    [[[self class] sharedView] removeGestureRecognizer:gesture];
}

NSDictionary *userInfo = [self notificationUserInfo];
[[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDWillDisappearNotification
                                                    object:nil
                                                  userInfo:userInfo];

self.activityCount = 0;
[UIView animateWithDuration:0.15
                      delay:0
                    options:UIViewAnimationCurveEaseIn | UIViewAnimationOptionAllowUserInteraction
                 animations:^{
                     self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 0.8, 0.8);
                     if(self.isClear) // handle iOS 7 UIToolbar not answer well to hierarchy opacity change
                         self.hudView.alpha = 0;
                     else
                         self.alpha = 0;
                 }
                 completion:^(BOOL finished){
                     if(self.alpha == 0 || self.hudView.alpha == 0) {
                         self.alpha = 0;
                         self.hudView.alpha = 0;

                         [[NSNotificationCenter defaultCenter] removeObserver:self];
                         [self cancelRingLayerAnimation];
                         [self addTapGestureToDismiss];
                         [_hudView removeFromSuperview];
                         _hudView = nil;

                         [_overlayView removeFromSuperview];
                         _overlayView = nil;

                         [_indefiniteAnimatedView removeFromSuperview];
                         _indefiniteAnimatedView = nil;


                         UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);

                         [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidDisappearNotification
                                                                             object:nil
                                                                           userInfo:userInfo];

                         // Tell the rootViewController to update the StatusBar appearance
                         UIViewController *rootController = [[UIApplication sharedApplication] keyWindow].rootViewController;
                         if ([rootController respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
                             [rootController setNeedsStatusBarAppearanceUpdate];
                         }
                         // uncomment to make sure UIWindow is gone from app.windows
                         //NSLog(@"%@", [UIApplication sharedApplication].windows);
                         //NSLog(@"keyWindow = %@", [UIApplication sharedApplication].keyWindow);
                     }
                 }];

}

My thought process is to add the tapGesture code to the dismiss method. This is what I have written so far.

- (void)addTapGestureToDismiss {

// Creation and initializer of the tap gesture
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc]
                                         initWithTarget:self action:@selector(dismiss)];

// Specify that the gesture must be a single tap
tapRecognizer.numberOfTapsRequired = 1;

// Add the tap gesture recognizer to the view
[[[self class] sharedView] addGestureRecognizer:tapRecognizer];

}

As you can see I'm just initializing the tapGesture. I've run into the issue of placing it in a few places and causing the app to only have one single tap. I've pretty much confused myself in the process. Should I

  • add this gesture to the view?
  • add this gesture to dismiss?

Building on Z.Hung's answer, you can make a category on SVProgressHUD so you don't have to repeat this code in every view controller that uses it.

Usage

Just import this category and call

[SVProgressHUD showDismissableErrorWithStatus:@"Error message here"];

Code

@interface SVProgressHUD (Dismissable)

+ (void)showDismissableErrorWithStatus:(NSString*)status;

@end

@implementation SVProgressHUD (Dismissable)

+ (void)showDismissableErrorWithStatus:(NSString*)status {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleHUDTappedNotification:) name:SVProgressHUDDidReceiveTouchEventNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleHUDDisappearedNotification:) name:SVProgressHUDWillDisappearNotification object:nil];
    [SVProgressHUD showErrorWithStatus: status];
}

#pragma mark - NSNotificationCenter

+ (void)handleHUDTappedNotification: (NSNotification *)notification {
    [SVProgressHUD dismiss];
}

+ (void)handleHUDDisappearedNotification: (NSNotification *)notification {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:SVProgressHUDDidReceiveTouchEventNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:SVProgressHUDWillDisappearNotification object:nil];

}

@end

Swift 4

import SVProgressHUD

/// Ref: https://stackoverflow.com/a/41111242/425694
extension SVProgressHUD {

  public static func showDismissableError(with status: String) {
    let nc = NotificationCenter.default
    nc.addObserver(
      self, selector: #selector(hudTapped(_:)),
      name: NSNotification.Name.SVProgressHUDDidReceiveTouchEvent,
      object: nil
    )
    nc.addObserver(
      self, selector: #selector(hudDisappeared(_:)),
      name: NSNotification.Name.SVProgressHUDWillDisappear,
      object: nil
    )
    SVProgressHUD.showError(withStatus: status)
    SVProgressHUD.setDefaultMaskType(.clear)
  }

  @objc
  private static func hudTapped(_ notification: Notification) {
    SVProgressHUD.dismiss()
    SVProgressHUD.setDefaultMaskType(.none)
  }

  @objc
  private static func hudDisappeared(_ notification: Notification) {
    let nc = NotificationCenter.default
    nc.removeObserver(self, name: NSNotification.Name.SVProgressHUDDidReceiveTouchEvent, object: nil)
    nc.removeObserver(self, name: NSNotification.Name.SVProgressHUDWillDisappear, object: nil)
    SVProgressHUD.setDefaultMaskType(.none)
  }

}

ios: Dismiss SVProgressHUD with Tap Gesture, I need to add a UITapGestureRecognizer to the SVProgressHUD. The SVProgressHUD already has the ability to dismiss using -(void) dismiss;. 10 Dismiss SVProgressHUD with Tap Gesture 7 With new XCode getting "Comparison of constant with boolean expression is always false" View more network posts →

UPDATE 2.0

After a while I stumbled upon this solution and remembered this question, it works as far as I have tested. Just add a Observer in your viewWillAppear of your ViewController class. No need to modify the library like my previous answer.

-(void)viewWillAppear:(BOOL)animated{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tapToDismiss:) name:SVProgressHUDDidReceiveTouchEventNotification object:nil];
    //Other initializing
}
-(void)tapToDismiss:(NSNotification *)notification{
    [SVProgressHUD dismiss];
    //maybe other code to stop whatever your progress is
}

This should dismiss the SVProgressHUD even if you have a masktype.

Use this to remove the Observer after you're done (like in the viewDidDisappear) or it will be there throughout the lifetime of the app.

[[NSNotificationCenter defaultCenter] removeObserver:self name:SVProgressHUDDidReceiveTouchEventNotification object:nil];

Credit: http://kevsaidwhat.blogspot.my/2013/06/cancel-svprogresshud-process-by-tapping.html

ios - 使用Tap Gesture解除SVProgressHUD, Dismiss SVProgressHUD with Tap Gesture. I need to add a UITapGestureRecognizer to the SVProgressHUD. The SVProgressHUD already has the ability to� Open up the configuration panel by using the app’s menubar item, and pick Magic Mouse from the top bar. Then, click on the + in the left column, and select One Finger Tap from the list. Then, in

The complete swift implementation someone maybe find it useful. This is the BaseViewController

func showProgressHud(){
    SVProgressHUD.show()
    SVProgressHUD.setDefaultMaskType(.clear)
}

func hideProgressHud(){
    SVProgressHUD.dismiss()
}


//Hide progress hud on user tap on unresponsive api call

func hideProgressHudOnUserTap(){
    NotificationCenter.default.addObserver(self, selector: #selector(self.tapToDismiss(notification:)), name: NSNotification.Name.SVProgressHUDDidReceiveTouchEvent, object: nil)
}

@objc func tapToDismiss(notification: Notification) {
    hideProgressHud()
}

func removeProgressHudObserver(){
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.SVProgressHUDDidReceiveTouchEvent, object: nil)
}

Then you call call it in your view controller like this

override func viewWillAppear(_ animated: Bool) {
    hideProgressHudOnUserTap()
}

override func viewDidDisappear(_ animated: Bool) {
    removeProgressHudObserver()
}

ios - 使用Tap Gesture解除SVProgressHUD, What I noticed from user-testing is that user tries to tap the HUD to hide it, but it //MARK: - Dismiss public func dismiss(){ SVProgressHUD.dismiss() } //MARK:� The tap gesture is used for tap detection and is implemented with the TapGestureRecognizer class. To make a user interface element clickable with the tap gesture, create a TapGestureRecognizer instance, handle the Tapped event and add the new gesture recognizer to the GestureRecognizers collection on the user interface element.

An easy way to implement this is by:

  1. creating a class that dismisses the HUD:
class HUDManager {
    @objc
    class func dismissHUD() {
        SVProgressHUD.dismiss()
    }
}
  1. Subscribing to the SVProgressHUDDidReceiveTouchEvent notification:
NotificationCenter.default.addObserver(HUDManager.self,
                                       selector: #selector(HUDManager.dismissHUD),
                                       name: .SVProgressHUDDidReceiveTouchEvent,
                                       object: nil)

Objective C - Lost with retain cycles, Мне нужно добавить UITapGestureRecognizer к SVProgressHUD . SVProgressHUD уже имеет возможность отклонить использование -(void) dismiss; . Android 11 DP1 added code for a new Pixel-exclusive double tap gesture called "Columbus" that could let you launch Google Assistant, the camera, and more.

Thanks @charmingToad, I would like to post a little more optimized and functional solution on top if here answer.

In my case I need to know the dismiss to cancel the operation if user taps and cancel.

import SVProgressHUD

extension SVProgressHUD {
    private static var dismissCompletion: (() -> ())?
    
    public static func showDismissable(with status: String, tapDismissed: (() -> ())? = nil) {
        dismissCompletion = tapDismissed
        
        let notificationCenter = NotificationCenter.default
        notificationCenter.addObserver(
            self, selector: #selector(hudTapped(_:)),
            name: NSNotification.Name.SVProgressHUDDidReceiveTouchEvent,
            object: nil
        )
        notificationCenter.addObserver(
            self, selector: #selector(hudDisappeared(_:)),
            name: NSNotification.Name.SVProgressHUDWillDisappear,
            object: nil
        )
        SVProgressHUD.show(withStatus: status)
        SVProgressHUD.setDefaultMaskType(.black)
    }

  @objc
  private static func hudTapped(_ notification: Notification) {
    SVProgressHUD.dismiss()
    SVProgressHUD.setDefaultMaskType(.none)
    dismissCompletion?()
  }

  @objc
  private static func hudDisappeared(_ notification: Notification) {
    dismissCompletion = nil
    let notificationCenter = NotificationCenter.default
    notificationCenter.removeObserver(self, name: NSNotification.Name.SVProgressHUDDidReceiveTouchEvent, object: nil)
    notificationCenter.removeObserver(self, name: NSNotification.Name.SVProgressHUDWillDisappear, object: nil)
    SVProgressHUD.setDefaultMaskType(.none)
  }
}

Touch to hide � Issue #76 � SVProgressHUD/SVProgressHUD � GitHub, Create an extension of the view controller. extension UIViewController {. func dismissKey(). {. let tap: UITapGestureRecognizer =� In France, this gesture is known as la barbe (”the beard”) and is the hand-sign equivalent of macho grandstanding. You should probably just never do this. (Photo: Kyrylo Glivin/Alamy) 2. The fig.

Отклонить SVProgressHUD с помощью жеста касания, SVProgressHUD에 UITapGestureRecognizer를 추가해야합니다. SVProgressHUD는 이미 -(void) dismiss;을 사용하여 닫을 수 있습니다. 이 코드는 초 단위로� Google tests new double tap gestures in Android 11 to take a screenshot or open the recent apps overview, and it could be coming to the Pixel 3 and Pixel 4.

Dismiss/Hide Keyboard by touching Anywhere outside UITextField , Long tap gesture is often referred to as tap and hold. For this Galaxy S9 touchscreen gesture, you need to tap the screen, then hold it for more than 2 seconds, as shown in the animation below. If you release your finger from the screen too early, it will be registered as a single tap gesture. The long tap gesture mimics the “right click

ios - 탭 제스처로 SVProgressHUD 닫기, That double-tap gesture could do thing like launch Google Assistant, take screenshots, dismiss a timer, play or pause music, snooze alarms, launch the camera, and more.

Comments
  • After taking a long look at this I found code that shows the image. I implemented some small test code: if (self.imageView ) { self.dismiss; } after implementing this test code the HudImage went away instantly after revealing itself. So my question now is, how do I write an if statement for a gesture in objec-c. I need to say, dismiss this if the user initiates a tap?
  • I had to put [SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeClear]; after showErrorWithStatus:.., after that it worked like a charm. Thanks!
  • That's the best way. First may we need to put SVProgressHUDMaskTypeClear... What happen if I put TypeNone?
  • I can't change anything about the dismiss method. It needs to stay there or all hudviews will stay on the screen. I need to simply add the feature of tapping the screen to dismiss the HUD if the user chooses to. How would you attach the addTapToDismiss to the view?
  • Have you tried to implement the code yet? The dismiss method here is just a local instance within the viewController class, it is not the same method as the dismiss method of the SVProgressHUD. It is simply calling the dismiss of the SVProgressHUD when screen is tapped. I'll edit my answer to include an option
  • In case I wasn't clear, my suggestion does not involve modifying the original SVProgressHUD library (including the dismiss method you posted). Just add the addTapToDismiss to your viewController class and call it whenever necessary.
  • it looks like I have some mask types in the code. Any other thoughts? I tried to implement the code in the BaseVC.m that we have and it didn't work. Any other thoughts?
  • Check my Updated answer suggesting modifying a library file