iOS:当点击 FormSheet 之外时,关闭该视图

@interface XXViewController (){
    
@property (strong, nonatomic) UITapGestureRecognizer *tapGesture;
- (void)handleTapGesture:(UITapGestureRecognizer *)gesture;
- (void)dismiss;
@end

@implementation XXViewController

- (void)dismiss
{
    [self dismissModalViewControllerAnimated:YES];
}

- (void)viewDidAppear:(BOOL)animated
{
    if (iPadIdiom) {
        if (self.tapGesture == nil) {
            UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
            self.tapGesture = tapGesture;
        }
        
        //将手势添加到 window 上
        if ([self.view.window.gestureRecognizers containsObject:self.tapGesture] == NO) {
            [self.view.window addGestureRecognizer:self.tapGesture];
        }
    }

    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
    //将手势从 window 上移除
    if ([self.view.window.gestureRecognizers containsObject:self.tapGesture]) {
        [self.view.window removeGestureRecognizer:self.tapGesture];
    }
    [super viewWillDisappear:animated];
}

- (void)handleTapGesture:(UITapGestureRecognizer *)gesture
{
    //因为是 TapGesture 的需要点击次数为 1,所以这个判断实际可以不写
    if (gesture.state == UIGestureRecognizerStateEnded) {
        //传 nil,gesture 会返回触碰点在 windiow 上的值
        CGPoint touchPoint = [gesture locationInView:nil];
        //将得到的坐标转换成与 self.view 相对应的坐标
        CGPoint convertPoint = [self.view convertPoint:touchPoint fromView:gesture.view];
        //判断触碰点是否在 self.view。bounse 中,如果在则返回,否则调用 dismiss 方法
        if (CGRectContainsPoint(self.view.bounds, convertPoint)) {
            return;
        }
        
        [self dismiss];
    }
}
@end

############# 更新 2014年07月24日13:11:06 ###############

之前的方法处理之后会有个小问题,presented 的 ViewController 如果有个列表,无法拿到点击事件(Button 没有测试,不知是否一样)

解决办法:

http://stackoverflow.com/a/12851794

1.设置 tapGestureRecognizer

tapGesture.cancelsTouchesInView = NO;

2.设置 gestureRecognizer 的 delegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
     shouldReceiveTouch:(UITouch *)touch
{
    if([touch.view class] == tableview.class){
        return //YES/NO
    }

    return //YES/NO

}

3.用 UIControl 代替 tapGestureRecognizer

- (void)viewDidAppear:(BOOL)animated
{
    if (iPadIdiom && self.dismissWhenTapOutsides) {
        if (tapControl == nil) {
            UIWindow *window = self.view.window;
            tapControl = [[UIControl alloc] initWithFrame:window.bounds];
            tapControl.backgroundColor = [UIColor clearColor];
            [window insertSubview:tapControl atIndex:[window.subviews count] - 1];
            [tapControl addTarget:self action:@selector(dismissOnTap) forControlEvents:UIControlEventTouchDown];
        }
    }
    
    [super viewDidAppear:animated];
}

- (void)dismissOnTap
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)viewWillDisappear:(BOOL)animated
{
    //将手势从 window 上移除
    if (self.dismissWhenTapOutsides) {

        if (tapControl && tapControl.superview) {
            [tapControl removeFromSuperview];
            tapControl = nil;
        }
    }

    [super viewWillDisappear:animated];
}
原文地址:https://www.cnblogs.com/ihojin/p/dismiss-formsheet-when-tap-outsides.html