ios-runtime攔截touch事件,展示使用者觸摸效果,ios-runtimetouch
【展示效果說明】
對 app 操作錄屏時,展示出手指在 app 上的觸摸效果可以看到具體點擊,感覺這樣比較方便,也不用做視頻後期了。
這裡簡單用 runtime 實現了一個這樣的效果,不需要修改任何代碼,只要將 UIWindow+Touch.m 分類匯入工程即可。
展示效果如下:
【實現思路】
1. 要攔截到所有的點擊事件,擷取點擊相對於螢幕的位置。ios中事件分發中點擊事件應該是這樣的: 系統第一個得到點擊事件 -> 分發給application -> 分發給 window -> window 內的子 view 層層遍曆。
2. 只是一個小功能,要讓這個功能可控,不要對原有代碼進行改動。用 runtime 交換系統方法,在分發事件時加入自己的一些代碼。
3. 拿到觸摸點的位置後建立 view 展示一些動畫效果就可以。
上面第1點中可以知道,事件在application中進行攔截最靠譜,因為系統第一個分發就是給它,這裡操作都是UI相關,所以UI相關事件放在 window 上進行處理比較。
【代碼】
建立 UIWindow + Touch 分類,在 .m 檔案中交換 sendEvent 方法,同時加上自己處理的代碼,主要是在擷取點擊x,y的位置,然後添加一個view,加上一點動畫,最終就有了上述效果。 UIWindow + Touch.m 代碼如下。
#import "UIWindow+Touch.h"#import <objc/runtime.h>@implementation UIWindow (Touch)+ (void)load{
// 交換方法 Method m1 = class_getInstanceMethod([self class], @selector(sendEvent:)); Method m2 = class_getInstanceMethod([self class], @selector(ljs_sendEvent:)); method_exchangeImplementations(m1, m2);}- (void)ljs_sendEvent:(UIEvent *)event{ [self ljs_sendEvent:event];
// 對點擊事件進行處理 [self dealTouch:event];}- (void)dealTouch:(UIEvent *)event{ UITouch *touch = event.allTouches.anyObject; if (touch.phase == UITouchPhaseEnded) { return; } static CGFloat width = 20; if (event.type == UIEventTypeTouches) { CGPoint point = [event.allTouches.anyObject locationInView:self]; CGFloat oringX = point.x - width / 2; CGFloat oringY = point.y - width / 2; CGRect rect = CGRectMake(oringX, oringY, width, width); UIView *blackV = [[UIView alloc] initWithFrame:rect]; blackV.alpha = 0.3; blackV.layer.cornerRadius = width / 2; blackV.backgroundColor = [UIColor purpleColor]; [self addSubview:blackV]; [self bringSubviewToFront:blackV]; // 設定動畫 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; animation.delegate = self; animation.duration = 0.3; animation.fromValue = @1; animation.toValue = @2; animation.fillMode = @"backwards"; animation.removedOnCompletion = YES; [blackV.layer addAnimation:animation forKey:@"an1"]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.27 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [blackV removeFromSuperview]; }); }}@end