前面分析了一通iOS事件的分發,主要介紹了事件如何找到處理的view,又是如何按照responder chain逐級傳遞的。這篇文章主要介紹iOS事件的攔截以及特殊處理。
我們知道事件的分發是由Application到Window再到各級View的,所以顯然最安全可靠的攔截地方是Application。這裡攔截事件後如果不手動往下分發,則進入hit-test View過程的機會都沒有。
UIApplication和UIWindow都有sendEvent:方法,用來分發Event。我們可以繼承類,重新實現sendEvent:方法,這樣就可以攔截下事件,完成一些特殊的處理。
比如:有一個iPad應用,要求在非某個特定view的區域觸摸時進行一項處理。
我們當然可以在其余每一個view裡面增加代碼進行判斷,不過這樣比較累,容易漏掉一些地方;另外當UI需求變更時,維護的GG往往會栽進這個坑,顯然這不是一個好方法。
這裡比較簡單的解決方案就是在繼承UIApplication類,實現自己的sendEvent:,在這個方法裡面初步過濾一下事件,是觸摸事件就發送Notification,而特定的view會注冊這個Notification,收到後判斷一下是否觸摸到了自己之外的區域。
恩,還是上代碼吧,比較清楚一點:
1. 繼承UIApplication的DPApplication類
#importextern NSString *const notiScreenTouch; @interface DPApplication : UIApplication @end
#import "DPApplication.h" NSString *const notiScreenTouch = @"notiScreenTouch"; @implementation DPApplication - (void)sendEvent:(UIEvent *)event { if (event.type == UIEventTypeTouches) { if ([[event.allTouches anyObject] phase] == UITouchPhaseBegan) { [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:notiScreenTouch object:nil userInfo:[NSDictionary dictionaryWithObject:event forKey:@"data"]]]; } } [super sendEvent:event]; } @end2.要在main.m文件中替換掉UIApplication的調用
#import3. 這時已經實現了攔截消息,並在touchBegan的時候發送Notification,下面就是在view裡面注冊這個Notification並處理#import "AppDelegate.h" #import "DPApplication.h" int main(int argc, char *argv[]) { @autoreleasepool { //return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); return UIApplicationMain(argc, argv, NSStringFromClass([DPApplication class]), NSStringFromClass([AppDelegate class])); } }
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onScreenTouch:) name:notiScreenTouch object:nil];
- (void)onScreenTouch:(NSNotification *)notification { UIEvent *event=[notification.userInfo objectForKey:@"data"]; NSLog(@"touch screen!!!!!"); CGPoint pt = [[[[event allTouches] allObjects] objectAtIndex:0] locationInView:self.button]; NSLog(@"pt.x=%f, pt.y=%f", pt.x, pt.y); }