剛學完uiview,uicontrol類,許多人知道 touchesBegain,touchesMoved,touchesEnd,GestureRecognizer的用途,但仔細考慮這些事件之間的關系,卻令人頭疼.
現在以一個例子來分析它們的內部實現:
- (void)viewDidLoad
{
UIButton * btn=[[UIButton alloc]initWithFrame:CGRectMake(20, 40, 50, 50)];
[self.view addSubview:btn];
btn.backgroundColor=[UIColor redColor];
[btn release];
UITapGestureRecognizer * tap11=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapmethod11:)];
[btn addGestureRecognizer:tap11];
[btn addTarget:self action:@selector(bthmethod:) forControlEvents:UIControlEventTouchUpInside];
//注意標紅得這三句,下面會對其重點分析
}
-(void)tapmethod11:(UITapGestureRecognizer *)tap
{
NSLog(@"%@",tap);
}
-(void)bthmethod:(UIButton *)btn
{
NSLog(@"%@",btn);
}
在一個視圖控制器viewDidLoad里面實例化一個button按鈕, 添加兩個事件 一個UIControlEventTouchUpInside,另一個手勢事件UITapGestureRecognizer,
啟動后單擊會發現,程序只會執行手勢事件
這是怎么回事?
首先先來分析UIButton這個類,這個類間接繼承於UIView,那么UIButton里面就一定有
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
....
這幾個事件
接下來看 [btn addTarget:self action:@selector(bthmethod:) forControlEvents:UIControlEventTouchUpInside]; 這句代碼,
這句代碼是當btn觸發這個 UIControlEventTouchUpInside(鼠標單擊事件)時,會觸發當前控制器里面的bthmethod:這個方法.
那么在UIButton這個類中也就肯定有 [self performSelector:bthmethod: withObject:self ]這句代碼
問題的關鍵就在這里,UIControlEventTouchUpInside 這個事件是在哪里觸發的哪? 可以做一個實驗(大家可以在自己電腦上試試),當單擊這個按鈕時,NSLOG打印出來的信息是在鼠標單擊鍵彈起后打印出來,所有可以推斷出 [self performSelector:bthmethod: withObject:self ]這句代碼是寫在 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 這個事件中(這里之所以確定是在事件中,因為這個委托方法一定是事件觸發的)
所以touchesEnded代碼先這樣寫
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self performSelector:bthmethod: withObject:self ];
}
下面在分析手勢識別GestureRecognizer
手勢識別繼承於NSObject,似乎和UIButton沒半點關聯,但仔細分析會發現:
UITapGestureRecognizer * tap11=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapmethod11:)];
手勢識別的初始化(此處以UITapGestureRecognizer為例) 和 addtarget action這個方法類似
說明在手勢識別這個類中,同樣會有 [self performSelector:tapmethod11: withObject:self ];這句代碼
但手勢識別不是繼承於UIView,所有它沒有touch事件
我們先假設他的類中有一個method1方法,那么代碼可以這樣表達
@implement UITapGestureRecognizer
-(void)method
{
[self performSelector:tapmethod11: withObject:self ];
}
@end
大家應該知道,這個方法並非事件方法,那么平白無故是不可能被調用,但我們在單擊按鈕時卻觸發了,原因是什么?
接下來看 [btn addGestureRecognizer:tap11];這句,這時UIButton的一個方法
UIButton中調用這個方法,就可以實現手勢識別
可以推斷出UIButton中有一個 私有字段 UIGestureRecognizer * gesture;(為什么是私有,因為是共有我們就可以在它的定義中看到)
那么上面的[btn addGestureRecognizer:tap11];就是給 gesture賦值
賦值后gesture 調用 method方法就會指向上面的事件
具體代碼如下:
@interface UIButton()
{
UIGestureRecognizer * gesture;
}
@end
@implementation UIButton
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[gesture method];
[self performSelector:bthmethod: withObject:self ];
}
@end
我們現在已經推理處touchesEnded里面有兩句代碼
但是單擊按鈕只執行了gesture 的方法,所有代碼經過改進如下,得到如下結論
@implementation UIButton
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if(gesture!=nil)
{
[gesture method];
}
else
{
[self performSelector:bthmethod: withObject:self ];
}
}
@end
這就解釋了開始我們提出的問題,為什么手勢和單擊事件只會響應手勢
其實經過以上的推理,我們也就可以解釋gesture為什么也會有手勢開始( UIGestureRecognizerStateBegan),改變( UIGestureRecognizerStateChanged,),結束( UIGestureRecognizerStateEnded, )等狀態
因為它完全就是UIView事件的生命周期的副本
那么UIButton類的最終版本是:
@interface UIButton()
{
UIGestureRecognizer * gesture;
}
@end
@implementation UIButton
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[gesture method];
[self performSelector:bthmethod: withObject:self ];
}
@end
我們現在已經推理處touchesEnded里面有兩句代碼
但是單擊按鈕只執行了gesture 的方法,所有代碼經過改進如下,得到如下結論
@implementation UIButton
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if(gesture!=nil)
{
gesture.state=UIGestureRecognizerStateEnded;
[gesture method];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if(gesture!=nil)
{
gesture.state=UIGestureRecognizerStateChanged;
[gesture method];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if(gesture!=nil)
{
gesture.state=UIGestureRecognizerStateBegan;
[gesture method];
}
else
{
[self performSelector:bthmethod: withObject:self ];
}
}
....
@end
以上是本人寫代碼時推斷的,當然手勢識別有各種類型,不可能僅僅這幾行代碼就能實現.
如有錯誤之處,請指出,共同進步