天天看點

iOS事件響應控制(一)

以前遇到一個項目,一個UIImageView對象上面有一個UIButton對象,然而項目的需求需要在點選 button的同時,UIImageView也接收到點選事件,在不使用代理和通知方法的前提下,通過事件響應鍊的原理,我們也可以很便捷的解決這個問題。

   在處理這個問題之前,我們應該先清楚IOS的事件響應機制到底是個什麼樣的原理。

首先,這個事件響應的機制是分為兩個部分的。

1、先在視圖層級關系中找到應該響應事件的那個視圖。

這一步是什麼意思,其實很簡單,就是找到你所觸摸點對應的那個最上層的視圖,它的工作原理是這樣的:當使用者發出事件後,會産生一個觸摸事件,系統會将該事件加入到一個由UIApplication管理的事件隊列中,UIApplication會取出隊列中最前面的事件,發消息給UIWindow,然後UIWindow會對其所有子視圖調用hitTest:withEvent:這個方法,這個方法會傳回一個UIView的對象,這個方法在執行的時候,它會調用目前視圖的pointInside:withEvent:這個方法,如果觸摸事件在目前視圖範圍内,pointInside:withEvent:會傳回YES,否則會傳回NO;如果傳回YES,則會周遊目前視圖的所有子視圖,統統發送hitTest:withEvent:這個消息,如果傳回NO,則hitTest:withEvent:方法傳回nil;

上面說起來有些繞,其實就是:hitTest:withEvent:方法會一層一層的向上找,若最上層響應的子視圖pointInside:withEvent:傳回YES,則傳回此子視圖,如果所有的都傳回nil,則傳回目前視圖本身self。

例如:我們建兩個檔案,一個繼承于UIButton,一個繼承于UIImageView,我們在UIImageView裡的代碼如下:

#import "MyImageView.h"

@implementation MyImageView

- (instancetype)initWithFrame:(CGRect)frame

{

   self = [super initWithFrame:frame];

   if (self) {

       self.backgroundColor=[UIColor redColor];

   }

   return self;

}

//在這裡,我們重寫了這個方法,讓它直接傳回自身,而不是繼續向下尋找應該響應事件的視圖

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

   NSLog(@"點選了Image");

然後将他們建立在一個View上:

- (void)viewDidLoad {

   [super viewDidLoad];

   MyImageView * image = [[MyImageView alloc]initWithFrame:CGRectMake(60, 80, 200, 200)];

   MyButton * btn =[UIButton buttonWithType:UIButtonTypeSystem];

   btn.frame=CGRectMake(20, 20, 40, 40);

   [btn setTitle:@"button" forState:UIControlStateNormal];

   [image addSubview:btn];

   [self.view addSubview:image];

   // Do any additional setup after loading the view, typically from a nib.

我們運作,點選這個Btn,會列印如下的資訊:

iOS事件響應控制(一)

可以證明,在事件視圖尋找中,UIImageView我們重寫hitTest:withEvent:方法後,切斷了尋找鍊,如果我們這個做:

   return nil;

你會發現,UIImageView也不再接收事件。

繼續閱讀