一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第25天,点击查看活动详情。
支持更多控件
支持UISwitch、UISegmentedControl、UIStepper控件
这些控件都不响应UIControlEventTouchDown类型的Action,也就是说,没有触发-sensorsdata_touchDownAction:event:方法,因此,也就不会触发$AppClick事件。实际上,这些控件添加的是 UIControlEventValueChanged类型的Action。
+ (void)load {
[UIControl sensorsdata_swizzleMethod:@selector(didMoveToSuperview) withMethod:@selector(CountData_didMoveToSuperview)];
}
- (void)CountData_didMoveToSuperview {
//调用前交换原始方法
[self CountData_didMoveToSuperview];
//判断是否为一些特殊的控件
if([self isKindOfClass:[UISwitch class]] ||
[self isKindOfClass:[UISegmentedControl class]] ||
[self isKindOfClass:[UIStepper class]]
) {
[self addTarget:self action:@selector(countData_valueChangedAction:event:) forControlEvents:UIControlEventValueChanged];
}else {
[self addTarget:self action:@selector(CountData_touchDownAction:withEvent:) forControlEvents:UIControlEventTouchDown];
}
}
-(void)countData_valueChangedAction:(UIControl *)sender event:(UIEvent *)event {
if ([self CountData_isAddMultipleTargetActionsWithDefaultEvent:UIControlEventValueChanged]) {
[[SensorsAnalyticsSDK sharedInstance]track:@"appclick" properties:nil];
}
}
-(BOOL)CountData_isAddMultipleTargetActionsWithDefaultEvent:(UIControlEvents)defaultEvent {
///如果有多个target,说明除了添加的target,还有其他
///那么返回YES,触发$AppClick事件
if (self.allTargets.count > 2) {
return YES;
}
//如果控件本身为target,并且添加了不是UIControlEventTouchDown类型的Action
//说明开发者以控件本身为target,并且已添加添加Action
//那么返回YES,触发$AppClick事件
if((self.allControlEvents & UIControlEventAllEvents) != UIControlEventTouchDown) {
return YES;
}
//如果控件本身为Target,并且添加了两个以上的UIControlEventTouchDown类型的Action
//说明开发者自行添加了Action
//那么返回YES,触发$AppClick事件
if([self actionsForTarget:self forControlEvent:defaultEvent].count > 2) {
return YES;
}
return NO;
}
支持UISlider控件
给UISlider添加的是UIControlEventTouchDown 类型的Action,这会导致在只点击而没有滑动UISlider时,也会触发 $AppClick事件,我们更希望只有手停止滑动UISlider时,才触发$AppClick事件。因此,需要修改UIControl+SensorsData.m文件中的- sensorsdata_didMoveToSuperview方法,默认也给UISlider添加UIControlEventValueChanged类型的Action。
- (void)CountData_didMoveToSuperview {
//调用前交换原始方法
[self CountData_didMoveToSuperview];
//判断是否为一些特殊的控件
if([self isKindOfClass:[UISwitch class]] ||
[self isKindOfClass:[UISegmentedControl class]] ||
[self isKindOfClass:[UIStepper class]] ||
[self isKindOfClass:[UISlider class]]) {
[self addTarget:self action:@selector(countData_valueChangedAction:event:) forControlEvents:UIControlEventValueChanged];
}else {
[self addTarget:self action:@selector(CountData_touchDownAction:withEvent:) forControlEvents:UIControlEventTouchDown];
}
}
在滑动UISlider过程中,会一直触发$AppClick事件。因此,我们还需要修改UIControl+CountData.m文件中 的-CountData_valueChanged Action:event:方法,确保如果是UISlider控件, 只有在手抬起的时候才触发$AppClick事件。
-(void)countData_valueChangedAction:(UIControl *)sender event:(UIEvent *)event {
if ([sender isKindOfClass:UISlider.class] && event.allTouches.anyObject.phase != UITouchPhaseEnded) {
return;
}
if ([self CountData_isAddMultipleTargetActionsWithDefaultEvent:UIControlEventValueChanged]) {
[[SensorsAnalyticsSDK sharedInstance]track:@"appclick" properties:nil];
}
}
这样处理之后,当我们滑动UISlider时,只会在手抬起时触发 $AppClick事件。
方案总结
方案一和方案二其实都运用了iOS中的Target- Action模式,这两种方案各有优劣。
- 对于方案一:如果给一个控件添加了多个
Target-Action,会导致多次触发$AppClick事件。 - 对于方案二:由于SDK为控件添加了一个默认触发类型的
Action,因此,如果开发者在开发 过程中使用UIControl类的allTargets或者allControlEvents属性进行逻辑判断,有可能会引入一些无法预料的问题。 因此,在选择方案的时候,读者可以根据自 己的实际情况和需求,来确定最终的实现方案。