0

按鈕的觸摸事件所以我有具有容器視圖的視圖控制器。容器視圖嵌入了導航控制器,該控制器也是視圖控制器的父控制器。故事板是這樣的:安裝有容器視圖敲擊手勢識別器不阻擋在容器的視圖,但塊的工具欄按鈕的觸摸事件

視圖控制器(mainViewController) - >導航控制器 - >視圖控制器(contentViewController

可以看到故事板的屏幕截圖中的下方。

第一箭頭是從容器視圖一個嵌入到賽格瑞導航控制器。第二個箭頭是代表contentViewController的關係是導航控制器的根視圖控制器。

mainViewControllercontentViewController是同一類的對象,名爲testViewController。它是UIViewController的子類。它的實現很簡單。它只有三個IBAction方法,沒有別的。下面是實現代碼:

#import "TestViewController.h" 

@implementation TestViewController 

- (IBAction)buttonTapped:(id)sender { 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil 
                message:@"button is tapped" 
                delegate:self 
              cancelButtonTitle:@"OK" 
              otherButtonTitles:nil]; 
    [alert show]; 
} 

- (IBAction)barButtonTapped:(id)sender 
{ 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil 
                message:@"bar button is tapped" 
                delegate:self 
              cancelButtonTitle:@"OK" 
              otherButtonTitles:nil]; 
    [alert show]; 
} 

- (IBAction)viewTapped:(id)sender { 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil 
                message:@"view is tapped" 
                delegate:self 
              cancelButtonTitle:@"OK" 
              otherButtonTitles: nil]; 
    [alert show]; 
}   
@end 

我在mainViewController加入敲擊手勢識別器到容器視圖。當點擊容器視圖時,它將viewTapped:(id)sender消息發送到mainViewController。內部的contentViewController根視圖的,有一個按鈕時輕敲它發送buttonTapped:(id)sender消息contentViewController。並且存在的contentViewController工具欄抽頭時,它發送barButtonTapped:(id)sender消息contentViewController在欄按鈕。最初的場景是mainViewController。當應用程序運行時,我發現只有酒吧按鈕的觸摸事件被阻止,觸摸事件被按鈕正確處理。在蘋果公司的文檔,Regulating the Delivery of Touches to Views,它說:

在簡單情況下,當觸摸時,觸摸對象從UIApplication對象到一個UIWindow對象傳遞 。然後,窗口 首先發送到觸摸任何手勢識別附其中 這些觸摸發生視圖(或到該視圖的superviews),它通過 觸摸視圖對象本身之前。

我想觸摸事件將不會傳遞到按鈕。這真讓我困惑。有人可以解釋這種行爲嗎?非常感謝你。


截圖故事板的: the storyboard

回答

3

Event Handling Guide for iOS: Event Delivery: The Responder Chain的‘響應鏈按照特定的傳送路徑’部分描述事件如何觸摸首先傳遞到被觸摸的視圖,然後通過它的所有超級視圖,然後到窗口,最後到應用程序本身。

項目的視圖層次的簡化表示應該是:

mainViewController's Root View 
    | mainViewController's Container View (has Tap Gesture Recognizer) 
    | | UINavigationController's Root View 
    | | | contentViewController's View 
    | | | | UIButton ("Button") 
    | | | UINavigationController's Toolbar View 
    | | | | UIToolbarTextButton ("Item") 

......所以,當你點擊按鈕或工具欄按鈕,他們之前mainViewController的容器視圖接收觸摸事件。

之所以按鈕的事件觸發和工具欄按鈕的不似乎與Event Handling Guide for iOS: Gesture Recognizers「‘與其他用戶界面控件交互’部分:

在iOS系統6.0及更高版本,默認的控制動作防止重疊的手勢識別器行爲。例如,按鈕的默認操作是單擊。如果您將一個輕擊手勢識別器附加到按鈕的父視圖,並且用戶點擊該按鈕,則按鈕的操作方法將接收觸摸事件而不是手勢識別器。

這似乎解釋了爲什麼UIButton能夠搶佔輕拍手勢識別器,但它沒有說明有關工具欄按鈕的任何明確內容。

如果打印出視圖層次結構,您會發現工具欄按鈕使用UIToolbarButton表示,這是一個直接從UIControl繼承的私有類。基於我們的觀察,我們假設UIToolbarButton不會搶佔像UIControl子類那樣的公開手勢識別器。當我調用touchesCancelled:withEvent:方法時,我發現在點擊手勢識別器觸發後它會被調用,這似乎是基於iOS的事件處理指南:手勢識別器的「手勢識別器獲得識別觸摸的第一次機會」部分他們指出:

...如果手勢識別器識別觸摸手勢,則窗口從來沒有提供觸摸對象的視圖,並同時取消觸摸對象先前發送到了一部分的觀點那個認可的序列。

有幾種不同的方法可以修改此行爲,而您選擇的方法取決於您的最終目標。如果您想允許在工具欄上觸摸,您可以檢查發送到手勢識別器的代表gestureRecognizer:shouldReceiveTouch:UITouch是否在工具欄的框架內,如果是,則返回NO。阻止接觸到UIButton明確可能需要子類化,但是如果要阻止所有接觸到mainViewController的子視圖控制器,則可以在其容器視圖上添加透明視圖。

相關問題