MyEventHandler.h
@interface MyEventHandler : UIView <UIGestureRecognizerDelegate>
@property (strong, nonatomic) NSMutableArray *touchCouple;
@property (strong, nonatomic) NSMutableArray *touchEvents;
@property (assign, nonatomic) SMonService *refSMonService;
@property (strong, nonatomic) NSMutableArray *controllerStack;
@property (strong, nonatomic) NSMutableArray *updatedCallStack;
@end
MyEventHandler.m
@implementation MyEventHandler
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.touchEvents = [[NSMutableArray alloc] init];
self.touchCouple = [[NSMutableArray alloc] init];
self.controllerStack = [NSMutableArray new];
self.updatedCallStack = [NSMutableArray new];
}
return self;
}
- (void)dealloc {
NSLog(@"%s", __PRETTY_FUNCTION__);
}
// hitTest 처리할 뷰컨트롤러 리턴
- (UIViewController *)hitTestViewController:(UIViewController*)viewController {
UIViewController *hitTestVC = nil;
if (viewController.navigationController) {
hitTestVC = viewController.navigationController;
} else if (viewController.tabBarController) {
hitTestVC = viewController.tabBarController;
} else {
return viewController;
}
return hitTestVC;
}
// hitTest 뷰 리턴
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIViewController *visibleVC = [_refSMonService topViewController];
UIViewController *hitTestVC = [self hitTestViewController:visibleVC];
CGPoint convPoint = [self convertPoint:point toView:hitTestVC.view];
UIView *handlerView = [hitTestVC.view hitTest:convPoint withEvent:event];
if (_touchCouple.lastObject && [_touchCouple.lastObject doubleValue] != event.timestamp) {
[_touchCouple removeAllObjects];
}
[_touchCouple addObject:[NSNumber numberWithDouble:event.timestamp]];
if (_touchCouple.count == 2) {
[_touchCouple removeAllObjects];
UIViewController *vc = [_refSMonService getViewControllerFromView:handlerView];
__block NSString *title = nil;
if ([handlerView isKindOfClass:[UIButton class]]) {
title = [(UIButton *)handlerView titleForState:UIControlStateNormal];
}
else if ([handlerView isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
title = [[[handlerView valueForKey:@"tabBar"] valueForKey:@"selectedItem"] title];
NSLog(@"TouchEvent raised: %f, %@ (view:%@-\"%@\", controller:%@)", event.timestamp, NSStringFromCGPoint(point), handlerView.class, title, vc.class);
});
[self processAfterTouch];
return handlerView;
}
else if ([vc isKindOfClass:[UIAlertController class]]) {
title =[[handlerView valueForKey:@"action"] title];
}
else {
}
NSLog(@"TouchEvent raised: %f, %@ (view:%@-\"%@\", controller:%@)", event.timestamp, NSStringFromCGPoint(point), handlerView.class, title, vc.class);
[self processAfterTouch];
}
return handlerView;
}
// 터치이벤트가 발생한후에 뷰스텍 변화 감지
- (void)processAfterTouch {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.8f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self detectViewControllerStackChange];
});
}
- (void)detectViewControllerStackChange {
[self exploreViewController:[_refSMonService getRootViewController]];
NSMutableSet *previousStack = [[[NSMutableSet alloc] initWithArray:_controllerStack] mutableCopy];
NSMutableSet *newStack = [[[NSMutableSet alloc] initWithArray:_updatedCallStack] mutableCopy];
[newStack minusSet:previousStack];
if (newStack.count) { // push
NSLog(@"%@ => %@", _controllerStack.lastObject, _updatedCallStack.lastObject);
}
previousStack = [[[NSMutableSet alloc] initWithArray:_controllerStack] mutableCopy];
newStack = [[[NSMutableSet alloc] initWithArray:_updatedCallStack] mutableCopy];
[previousStack minusSet:newStack];
if (previousStack.count) { // pop
NSLog(@"%@ <= %@", _updatedCallStack.lastObject, _controllerStack.lastObject);
}
if (newStack.count || previousStack.count) {
self.controllerStack = [_updatedCallStack mutableCopy];
}
[_updatedCallStack removeAllObjects];
}
- (void)exploreViewController:(UIViewController *)viewController {
[_updatedCallStack addObject:viewController];
if ( [viewController isKindOfClass:[UITabBarController class]] ) {
[self exploreViewController:[(UITabBarController *)viewController selectedViewController]];
}
else if ( [viewController isKindOfClass:[UINavigationController class]] ) {
for ( UIViewController *childVC in ((UINavigationController *)viewController).viewControllers ) {
[self exploreViewController:childVC];
}
} else if (viewController.presentedViewController) {
[self exploreViewController:viewController.presentedViewController];
}
}
@end
위의 클래스 사용방법 =>
+ (instancetype)sharedInstance
{
static dispatch_once_t once;
static SMon *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
// 화면 가로.세로 이벤트 받기
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:sharedInstance
selector:@selector(didRotateDeviceChangeNotification:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
// 이벤트 받기
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow];
sharedInstance.eventHandler = [[MyEventHandler alloc] initWithFrame:mainWindow.bounds];
sharedInstance.eventHandler.alpha = .2f;
sharedInstance.eventHandler.tag = 100;
sharedInstance.eventHandler.backgroundColor = [UIColor yellowColor];
[mainWindow addSubview:sharedInstance.eventHandler];
[sharedInstance runLoop];
});
});
return sharedInstance;
}
......
- (void)runLoop {
self.loopTimer = [NSTimer scheduledTimerWithTimeInterval: .5f
target: self
selector:@selector(checkPeriodically:)
userInfo: nil repeats:YES];
}
- (void)checkPeriodically:(NSTimer *)timer {
[self makeEnablingEventMonitoring];
}
// 터치 이벤트 로그를 기록하는 뷰가 최상위에 위치하는지 체크
- (void)makeEnablingEventMonitoring {
[self.eventHandler.superview bringSubviewToFront:self.eventHandler];
}
- (void)dealloc {
NSLog(@"%s", __PRETTY_FUNCTION__);
[_loopTimer invalidate];
_loopTimer=nil;
}
// 이벤트 핸들러 프레임 재 조정
-(void)didRotateDeviceChangeNotification:(NSNotification *)notification
{
self.deviceOrientation = [UIApplication sharedApplication].statusBarOrientation;
UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow];
[_eventHandler setFrame:mainWindow.bounds];
}
화면 출력 예제 :
2017-06-20 15:23:12.631433+0900 S-MonitorTest[2305:527739] TouchEvent raised: 118397.829529, {90.666656494140625, 175.66665649414062} (view:UITableViewCellContentView-"(null)", controller:ViewController)
2017-06-20 15:23:13.505765+0900 S-MonitorTest[2305:527739] (null) => <UITestMainViewController: 0x12bd44e90>
2017-06-20 15:23:15.134760+0900 S-MonitorTest[2305:527739] TouchEvent raised: 118400.333632, {119.66665649414062, 265} (view:UITableViewCellContentView-"(null)", controller:UITestMainViewController)
2017-06-20 15:23:16.006614+0900 S-MonitorTest[2305:527739] <UITestMainViewController: 0x12bd44e90> => <UITest3ViewController: 0x12bd58e40>
2017-06-20 15:23:20.316494+0900 S-MonitorTest[2305:527739] TouchEvent raised: 118405.515406, {372.66665649414062, 65.666656494140625} (view:UIButton-"Close", controller:UITest3ViewController)
2017-06-20 15:23:21.197020+0900 S-MonitorTest[2305:527739] <UITestMainViewController: 0x12bd44e90> <= <UITest3ViewController: 0x12bd58e40>
댓글 없음:
댓글 쓰기