iOS7 UIBarButtonItem 无法响应点击事件

作者: 沈冰忱 | 来源:发表于2016-08-19 13:43 被阅读1715次

    最近做项目时就碰到了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上,则进行相关处理,并返回。否则,还是原来的处理逻辑。

    相关文章

      网友评论

        本文标题:iOS7 UIBarButtonItem 无法响应点击事件

        本文链接:https://www.haomeiwen.com/subject/vnebsttx.html