Samhan Salahuddin
Samhan Salahuddin

Reputation: 2170

Dismiss a view when a user taps anywhere outside the view

I have a very complex app with lots of stacked views which contain lots of buttons ,drawing areas and other custom touch handling . I am displaying a draggable helper view which can be on top of all the other views . I need to dismiss this view if the user taps anywhere outside the helper view . I have tried using multiple UIWindows and adding Gesture recognizers to the UIWindow .

Upvotes: 8

Views: 17209

Answers (3)

GoInterface
GoInterface

Reputation: 95

create an hittestintercept view. this can make the view below handle events like before.

@protocol HitTestInterceptViewDelegate <NSObject>

- (BOOL)interceptHitTest:(CGPoint)point withEvent:(UIEvent *)event;

@end

@interface HitTestInterceptView : UIView

@property(nonatomic, weak) id<HitTestInterceptViewDelegate> hitTestInterceptDelegate;

@end

HtiTestInterceptView.m

#import "HitTestInterceptView.h"

@implementation HitTestInterceptView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if ([_hitTestInterceptDelegate interceptHitTest:point withEvent:event] == NO) {
        return [super hitTest:point withEvent:event];
    }
    return nil;
}

@end

then use it in the toast view

- (void)dismissIfTouchOutsideInView:(UIView *)view {
    if (_interceptView != nil) return;
    _interceptView = [[HitTestInterceptView alloc] initWithFrame:view.bounds];
    _interceptView.backgroundColor = [UIColor clearColor];
    _interceptView.hitTestInterceptDelegate = self;
    [view insertSubview:_interceptView belowSubview:self];
}

- (BOOL)interceptHitTest:(CGPoint)point withEvent:(UIEvent *)event {
    dispatch_async(dispatch_get_main_queue(), ^{
        // [self dismiss];
    });
    return YES;
}

Upvotes: 1

Balu
Balu

Reputation: 8460

You can check the view being touched by going through the touches and looking at the .view property of the touch. It reflects the view from where the view actually originates.

Assuming that you keep a reference to your view (either via an IBOutlet or otherwise) to your view called "myView" the below works.

In your .m file. The touchesBegan: function is triggered every time the user touches a finger down. We loop through the touches to see if the originating view of the touch is NOT equal to "myView". This comparison could also be done via checking the class, tag or any other property you use to identify your view. Examples given below.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event  {
    NSLog(@"touches began");
    UITouch *touch = [touches anyObject];   
    if(touch.view!=myView){
       myView.hidden = YES;
    }
}

Or in case of using a tag:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event  {
    NSLog(@"touches began");
    UITouch *touch = [touches anyObject];   
    if(touch.view.tag!=23){
       myView.hidden = YES;
    }
}

Upvotes: 8

Guo Luchuan
Guo Luchuan

Reputation: 4731

A easy is to add a transparent button which bounds is equal the superview's bounds. And the superview insert the transparent button below your helper view.

The transparent button add a click event which can dismiss the helper view and the transparent button it self.

For example :

UIButton *transparencyButton = [[UIButton alloc] initWithFrame:superview.bounds];
transparencyButton.backgroundColor = [UIColor clearColor];
[superview insertSubview:transparencyButton belowSubview:helperView];
[transparencyButton addTarget:self action:@selector(dismissHelper:) forControlEvents:UIControlEventTouchUpInside];

and the dismissHelper: method can do this :

- (void)dismissHelper:(UIButton *)sender
{
    [helperView dismiss];
    sender.hidden = YES;
    // or [sender removeFromSuperview]
}

Upvotes: 16

Related Questions