Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 .

like image 400
Samhan Salahuddin Avatar asked Apr 16 '13 10:04

Samhan Salahuddin


3 Answers

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]
}
like image 108
Guo Luchuan Avatar answered Nov 15 '22 20:11

Guo Luchuan


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;
    }
}
like image 43
Balu Avatar answered Nov 15 '22 21:11

Balu


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;
}
like image 29
GoInterface Avatar answered Nov 15 '22 19:11

GoInterface