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,334評論 0 0
  • 在iOS開發中經常會涉及到觸摸事件。本想自己總結一下,但是遇到了這篇文章,感覺總結的已經很到位,特此轉載。作者:L...
    WQ_UESTC閱讀 6,081評論 4 26
  • UIView用戶事件響應 UIView除了負責展示內容給用戶外還負責響應用戶事件。本章主要介紹UIView用戶交互...
    subite0閱讀 261評論 0 1
  • UIView除了負責展示內容給用戶外還負責響應用戶事件。本章主要介紹UIView用戶交互相關的屬性和方法。 1、交...
    yida9623閱讀 1,631評論 0 1
  • 好奇觸摸事件是如何從屏幕轉移到APP內的?困惑于Cell怎么突然不能點擊了?糾結于如何實現這個奇葩響應需求?亦或是...
    Lotheve閱讀 57,778評論 51 602