iOS開發(fā)者大都略知一二事件的傳遞機制,但是對于事件在處理過程中所調用的具體方法和方法所應用的場景是比較模糊的.今天我就簡單的介紹一下事件處理流程和具體的使用.
事件處理流程:
1.當用戶點擊屏幕時會產生一個觸摸事件,系統(tǒng)會將該事件包裝成一個UIEvent加入到一個由UIApplication管理的事件隊列中.
2.UIApplication會從事件隊列中取出最前面的事件進行分發(fā)以便處理,通常先發(fā)送給應用程序的主窗口(UIWindow)
3.主窗口會調用hitTest:withEvent:方法在視圖(UIView)層次結構中找到最適合的UIView來處理觸摸事件.(hitTest:withEvent其實也是UIView的一個方法,UIWindow繼承自UIView,因此主窗口UIWindow也是屬于視圖的一種)
hitTest:withEvent:方法大致處理流程時這樣的:
調用當前視圖的pointInside:withEvent:方法判斷觸摸點是否在當前視圖內:
- 若pointInside:withEvent:方法返回NO,說明觸摸點不在當前視圖內,則當前視圖的hitTest:withEvent:方法返回nil
- 若pointInside:withEvent:方法返回YES,說明觸摸點在當前視圖內,則遍歷當前視圖的子控件(subViews),然后調用子控件的hitTest:withEvent:和pointInside:withEvent:方法來判斷觸摸點是否在某個子控件上.子視圖的遍歷順序時top到bottom,即從subViews數組的末端向前遍歷,直到有子視圖的hitTest:withEvent:方法返回為非空對象或者全部子視圖遍歷完畢.
- 若第一次有子視圖的hitTest:withEvent:返回非空對象,則當前視圖的hitTest:withEvent:方法就返回此對象,處理結束
- 若所有的子視圖的hitTest:withEvent:方法返回nil,則當前視圖的hitTest:withEvent:返回當前視圖自身(self).
4.最終,這個觸摸事件交給主窗口的hitTest:withEvent方法返回的視圖對象去處理.
舉例:
1.擴大UIButton的響應區(qū)域(上下左右各增加10)
重寫UIButton的pointInside:withEvent:方法
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
if (CGRectContainsPoint(CGRectInset(self.bounds, -10, -10), point)) {
return YES;
}
return NO;
}
2.子控件超出父控件的bounds如何響應事件
一般超出部分是不會響應事件的,所以我們要重寫父控件的pointInside:withEvent:方法來處理
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
BOOL flag = NO;
for (UIView *view in self.subviews) {
if (CGRectContainsPoint(view.frame, point)){
flag = YES;
break;
}
}
return flag;
}