iOS事件拦截及应用

1.概述

  我们知道事件的分发是由Application到Window再到各级View的,所以显然最安全可靠的拦截地方是Application。这里拦截事件后如果不手动往下分发,则进入hit-test View过程的机会都没有。

  UIApplication和UIWindow都有sendEvent:方法,用来分发Event。我们可以继承类,重新实现sendEvent:方法,这样就可以拦截下事件,完成一些特殊的处理,也可以利用runtime,将sendEvent:方法替换为我们自己的方法,添加一些我们自己的实现,然后再调用原来的消息流程。

2.拦截方式

  1)利用runtime

#import "EventHookObject.h"

#import <objc/objc.h>

#import <objc/runtime.h>

@implementation EventHookObject

+ (void)initialize

{

    Method sendEvent = class_getInstanceMethod([UIApplication class], @selector(sendEvent:));

    Method mySendEvent = class_getInstanceMethod([self class], @selector(mySendEvent:));

    IMP sendEventIMP = method_getImplementation(sendEvent);

    class_addMethod([UIApplication class], @selector(sendEventOri:), sendEventIMP, method_getTypeEncoding(sendEvent));

    IMP mySendEventIMP = method_getImplementation(mySendEvent);

    class_replaceMethod([UIApplication class], @selector(sendEvent:), mySendEventIMP, method_getTypeEncoding(sendEvent));

}

 
/*

 * 截获到UIApplication的sendEvent

 * 我们可以先处理完以后,再继续调用正常处理流程

 */

- (void)mySendEvent:(UIEvent*)event {

    //这里可以添加一些你想要的处理

    [self performSelector:@selector(sendEventOri:) withObject:event];

}

 然后就是在函数- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions内调用即可

  2)继承UIApplication类,实现自己的sendEvent:

  应用场景如下,比如应用要求在非某个特定view的区域触摸时进行一项处理。

  我们当然可以在其余每一个view里面增加代码进行判断,不过这样比较累,容易漏掉一些地方,比较简单的解决方案就是在继承UIApplication类,实现自己的sendEvent:,在这个方法里面初步过滤一下事件,是触摸事件就发送Notification,而特定的view会注册这个Notification,收到后判断一下是否触摸到了自己之外的区域。

#import "EventApplication.h"
 
NSString *const NotificationScreenTouch = @"NotificationScreenTouch";
 
@implementation EventApplication
 
- (void)sendEvent:(UIEvent *)event
{
    if (event.type == UIEventTypeTouches) {

        if ([[event.allTouches anyObject] phase] == UITouchPhaseBegan) {

            [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:NotificationScreenTouch object:nil userInfo:[NSDictionary dictionaryWithObject:event forKey:@"value"]]];
        }
    }

    [super sendEvent:event];
}
 
@end

在main.m文件中替换掉UIApplication的调用

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "EventApplication.h"
 
int main(int argc, char *argv[])
{
    @autoreleasepool {
        //return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        return UIApplicationMain(argc, argv, NSStringFromClass([EventApplication class]), NSStringFromClass([AppDelegate class]));
    }
}

这样我们就实现了事件的预处理,抓住了源头,想做啥都可以。

  

原文地址:https://www.cnblogs.com/hlfme/p/4654966.html