iOS7 UIBarButtonItem 无法响应点击事件

最近做项目时就碰到了UIBarButttonItem无法响应点击事件的问题。

原因

找了原因才发现是因为在viewController.view上添加了UITapGestureRecognizer。然后那个Tap Recognizer捕获了所有的tap事件, 导至点击toolbar上的ButtonItem没响应。
看官可能会说,按respond chain, toolbar上的事件不应该会被tap recognizer捕获才对, toolbar是viewController.view的subView。可是不辛的是,ios7上就是这么不讲道理。

解决方案

  1. 移除Tap Recognizer
    如果可能的话,移除Tap Recognizer,toolbar就可以响应事件了。

  2. 利用UIGestureRecognizerDelegate来阻止Tap Recognizer捕获事件
    UIGestureRecognizerDelegate 有这么一个函数,用来决定gesture Recognizer要不要响应touch。
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch

我是这样做的:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if (touch.view.superview == self.datePicker.toolBar) {
        return NO;
    }
    return YES;
}

上面代码,如果touch发生在toolbar中,我们就让gesture recognizer忽略此touch。这样toolbar应该就能正常响应事件了。可是iOS7又再次不讲道理, 即便我返回了NO。tap recognizerd还是不要脸的捕获了事件!

好吧,算你狠。既然改变不了你,只好改变自己。我的方案是在tap recognizer的响应函数分析、并发送处理toolbar事件。

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if (touch.view.superview == self.datePicker.toolBar) {
        self.touch = touch;
        // only work for non ARC
//        NSString *title;
//        object_getInstanceVariable(touch, "_title", (void *)&title);
        // for ARC
        NSLog(@"%@",touch.view);
        Ivar titleIvar = class_getInstanceVariable([touch.view class], "_title");
        NSString *title = object_getIvar(touch.view, titleIvar);
        if ([title isEqualToString:@"完成"]) {
            self.datePickerDone = YES;
        } else if ([title isEqualToString:@"取消"]) {
            self.datePickerCanceled = YES;
        }
        return NO;
    }
    self.touch = nil;
    return YES;
}

- (void)dismissKeyboard:(UIGestureRecognizer *)gesture {
    if (self.touch) {
        if (self.datePickerCanceled) {
            [self.datePicker cancelBtnAction:self];
            self.datePickerCanceled = NO;
        }
        if (self.datePickerDone) {
            [self.datePicker doneBtnAction:self];
            self.datePickerDone = NO;
        }
        return;
    }
    [self.view endEditing:false];
}

在函数- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch中分析touch,如果发生在toolbar,则记录是哪个barButtonItem发生了点击。UIBarButtonItem只是存数据的model,真正创建toolbar时会根据UIBarButtonItem来创建view(UIToolbarButton),该view是私有类,我们不知道它的接口,打断时可以发现它有个_title变量,就是我们设置barButtonItem时设的title。我们可以根据这个变量来区分哪个barButtonItem被点击了。而如何在ARC下,获取类的私有变量:

Ivar titleIvar = class_getInstanceVariable([touch.view class], "_title");
NSString *title = object_getIvar(touch.view, titleIvar);

在记录了点击位置之后,我们就可以在tap的响应函数中进行处理,我这里是- (void)dismissKeyboard:(UIGestureRecognizer *)gesture。如果前面的delegate记录点击发生在toolbar上,则进行相关处理,并返回。否则,还是原来的处理逻辑。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一.Gesture Recognizers Gesture Recognizers是在iOS3.2引入的,可以用来...
    JackyHeWei阅读 1,343评论 0 0
  • 在iOS开发中经常会涉及到触摸事件。本想自己总结一下,但是遇到了这篇文章,感觉总结的已经很到位,特此转载。作者:L...
    WQ_UESTC阅读 6,146评论 4 26
  • UIView用户事件响应 UIView除了负责展示内容给用户外还负责响应用户事件。本章主要介绍UIView用户交互...
    subite0阅读 271评论 0 1
  • UIView除了负责展示内容给用户外还负责响应用户事件。本章主要介绍UIView用户交互相关的属性和方法。 1、交...
    yida9623阅读 1,726评论 0 1
  • 好奇触摸事件是如何从屏幕转移到APP内的?困惑于Cell怎么突然不能点击了?纠结于如何实现这个奇葩响应需求?亦或是...
    Lotheve阅读 58,270评论 51 603