前言
由于UIGestureRecognizer是一个抽象基类,所以它并不会处理具体的手势。因此,对于具体的手势触摸事件,需要使用相应的子类进行处理。
常见的具体手势识别器
UITapGestureRecognizer:轻拍手势
UILongPressGestureRecognizer:长按手势
UIPinchGestureRecognizer:捏合(缩放)手势
UIRotationGestureRecognizer:旋转手势
UISwipeGestureRecognizer:轻扫手势
UIPanGestureRecognizer:平移手势
UIScreenEdgePanGestureRecognizer:屏幕边缘平移手势
I、手势全埋点方案
接下来介绍如何实现手势识别的全埋点,来采集常见控件(UILabel、UIImageView)的轻拍和长按手势。
手势识别器使用了Target-Action设计模式,可调用UIView类中的-addGestureRecognizer:
方法进行添加手势识别器
当我们为一个手势识别器添加一个或多个Target-Action后,在视图上进行触摸操作时,一旦系统识别了该手势,就会向所有的Target(对象)发送消息,并执行Action(方法)
主要是通过如下两个方法进行添加手势识别器
- initWithTarget:target action: - addTarget:action:
addGestureRecognizer的使用例子
_tappedLabel.userInteractionEnabled = YES; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init]; [tap addTarget:self action:@selector(tapAction:)]; [_tappedLabel addGestureRecognizer:tap];
虽然手势操作和UIControl类一样,均使用了Target-Action设计模式,但手势识别器并不会将消息交由UIApplication对象来发送。因此无法使用与UIControl控件相同的处理方式(通过响应者链的方式来实现全埋点)
为了采集控件的轻拍手势,我们可以通过Method Swizzling在UITapGestureRecognizer类中添加Target-Action的方法,添加一个新的Target-Action,并在新添加的Action中触发Click事件,进而实现控件轻拍手势全埋点。
1.1 轻拍手势全埋点
#import "UIGestureRecognizer+SensorsData.h" #import "SensorsAnalyticsSDK.h" #import "NSObject+SASwizzler.h" @implementation UITapGestureRecognizer (SensorsData) + (void)load { // Swizzle initWithTarget:action: 方法 [UITapGestureRecognizer sensorsdata_swizzleMethod:@selector(initWithTarget:action:) withMethod:@selector(sensorsdata_initWithTarget:action:)]; // Swizzle addTarget:action: 方法 [UITapGestureRecognizer sensorsdata_swizzleMethod:@selector(addTarget:action:) withMethod:@selector(sensorsdata_addTarget:action:)]; } - (instancetype)sensorsdata_initWithTarget:(id)target action:(SEL)action { // 调用原始的初始化方法进行对象初始化 [self sensorsdata_initWithTarget:target action:action]; // 调用添加 Target-Action 方法,添加埋点的 Target-Action // 这里其实调用的是 sensorsdata_addTarget:action: 里的实现方法,因为已经进行了 swizzle [self addTarget:target action:action]; return self; } - (void)sensorsdata_addTarget:(id)target action:(SEL)action { // 调用原始的方法,添加 Target-Action [self sensorsdata_addTarget:target action:action]; // 新增 Target-Action,用于埋点 [self sensorsdata_addTarget:self action:@selector(sensorsdata_trackTapGestureAction:)]; } - (void)sensorsdata_trackTapGestureAction:(UITapGestureRecognizer *)sender { // 获取手势识别器的控件 UIView *view = sender.view; // 暂只采集 UILabel 和 UIImageView BOOL isTrackClass = [view isKindOfClass:UILabel.class] || [view isKindOfClass:UIImageView.class]; if (!isTrackClass) { return; } // Click事件的属性 NSDictionary *properties = @{@"$element_type": NSStringFromClass(self.class)}; // 触发Click 事件 [[SensorsAnalyticsSDK sharedInstance] trackAppClickWithView:view properties:properties]; } @end
1.2 长按手势全埋点
手势处于UIGestureRecognizerStateEnded状态时,才触发Click事件
@implementation UILongPressGestureRecognizer (SensorsData) + (void)load { // Swizzle initWithTarget:action: 方法 [UILongPressGestureRecognizer sensorsdata_swizzleMethod:@selector(initWithTarget:action:) withMethod:@selector(sensorsdata_initWithTarget:action:)]; // Swizzle addTarget:action: 方法 [UILongPressGestureRecognizer sensorsdata_swizzleMethod:@selector(addTarget:action:) withMethod:@selector(sensorsdata_addTarget:action:)]; } - (instancetype)sensorsdata_initWithTarget:(id)target action:(SEL)action { // 调用原始的初始化方法进行对象初始化 [self sensorsdata_initWithTarget:target action:action]; // 调用添加 Target-Action 方法,添加埋点的 Target-Action // 这里其实调用的是 sensorsdata_addTarget:action: 里的实现方法,因为已经进行了 swizzle [self addTarget:target action:action]; return self; } - (void)sensorsdata_addTarget:(id)target action:(SEL)action { // 调用原始的方法,添加 Target-Action [self sensorsdata_addTarget:target action:action]; // 新增 Target-Action,用于埋点 [self sensorsdata_addTarget:self action:@selector(sensorsdata_trackLongPressGestureAction:)]; } - (void)sensorsdata_trackLongPressGestureAction:(UILongPressGestureRecognizer *)sender { if (sender.state != UIGestureRecognizerStateEnded) { return; } // 获取手势识别器的控件 UIView *view = sender.view; // 暂定只采集 UILabel 和 UIImageView BOOL isTrackClass = [view isKindOfClass:UILabel.class] || [view isKindOfClass:UIImageView.class]; if (!isTrackClass) { return; } NSDictionary *properties = @{@"$element_type": NSStringFromClass(self.class)}; // 触发Click 事件 [[SensorsAnalyticsSDK sharedInstance] trackAppClickWithView:view properties:properties]; } @end
II 、右划返回的事件与scrollView滚动事件冲突的解决方案
- 通过 requireGestureRecognizerToFail方法来处理。
将两个手势依次处理, 一个校验失败,再执行另外一个手势的校验,以解决手势冲突.
[_bigScrollView.panGestureRecognizer requireGestureRecognizerToFail:self.navigationController.interactivePopGestureRecognizer];