Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
//
// UIViewController+DismissOnTapOutside.h
// Telly
//
// Created by Mazyad Alabduljaleel on 5/8/14.
// Copyright (c) 2014 Telly, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIViewController (DismissOnTapOutside)
- (void)registerForDismissOnTapOutside; // Call in viewDidAppear
- (void)unregisterForDismissOnTapOutside; // Call in viewWillDisappear
@end
//
// UIViewController+DismissOnTapOutside.m
// Telly
//
// Created by Mazyad Alabduljaleel on 5/8/14.
// Copyright (c) 2014 Telly, Inc. All rights reserved.
//
#import "UIViewController+DismissOnTapOutside.h"
#import <objc/runtime.h>
static char gestureRecognizerKey;
static char gestureRecognizerDelegateKey;
@interface SimpleGestureRecognizerDelegate : NSObject <UIGestureRecognizerDelegate>
@end
@implementation SimpleGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return ![otherGestureRecognizer.view isKindOfClass:NSClassFromString(@"UIDimmingView")];
}
@end
@interface UIViewController ()
@property (assign, nonatomic) UIGestureRecognizer *gestureRecognizer;
@property (strong, nonatomic) SimpleGestureRecognizerDelegate *gestureRecognizerDelegate;
@end
@implementation UIViewController (DismissOnTapOutside)
- (void)setGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
objc_setAssociatedObject(self, &gestureRecognizerKey, gestureRecognizer, OBJC_ASSOCIATION_ASSIGN);
}
- (UIGestureRecognizer *)gestureRecognizer
{
return objc_getAssociatedObject(self, &gestureRecognizerKey);
}
- (void)setGestureRecognizerDelegate:(SimpleGestureRecognizerDelegate *)delegate
{
objc_setAssociatedObject(self, &gestureRecognizerDelegateKey, delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIGestureRecognizer *)gestureRecognizerDelegate
{
id delegate = objc_getAssociatedObject(self, &gestureRecognizerDelegateKey);
if (!delegate)
{
delegate = [[SimpleGestureRecognizerDelegate alloc] init];
self.gestureRecognizerDelegate = delegate;
}
return delegate;
}
- (void)handleDismissTap:(UIGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateEnded)
{
UIView *view = self.navigationController.view ?: self.view;
CGPoint location = [touch locationInView:view];
if (![view pointInside:location withEvent:nil])
{
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
}
}
- (void)registerForDismissOnTapOutside
{
// This approach is attributed to Danilo Campos:
// http://stackoverflow.com/a/6180584/456434
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDismissTap:)];
recognizer.delegate = self.gestureRecognizerDelegate;
recognizer.numberOfTapsRequired = 1;
recognizer.cancelsTouchesInView = NO;
self.gestureRecognizer = recognizer;
[self.view.window addGestureRecognizer:recognizer];
}
- (void)unregisterForDismissOnTapOutside
{
[self.view.window removeGestureRecognizer:self.gestureRecognizer];
self.gestureRecognizer = nil;
}
@end
@dminones

This comment has been minimized.

Copy link

@dminones dminones commented Dec 5, 2014

This is great!!
I have used on my own project, you should add this to delegates (works better with uinavigationcontroller subclassing)

  • (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    return [touch.view isKindOfClass:NSClassFromString(@"UIDimmingView")];;
    }

I will fork to solve this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment