UISlider添加单击事件(利用runtime机制)
原生UISlider用作进度条时没有提供单击事件的接口,通过继承在子类中实现单击事件又有杀鸡用牛刀的感觉,于是考虑在Category中实现。
创建UISlider+touch.h和UISlider+touch.m文件,添加单击事件方法:
1 @interface UISlider (touch) 2 // 单击手势 3 - (void)addTapGestureWithTarget:(id)target 4 action:(SEL)action; 5 @end
实现原理是为UISlider对象添加UITapGestureRecognizer,当触发tap事件时利用传入的target和action回调单击事件。
在Category添加方法很简单,但是要扩展属性以保存传入的target和action两个参数就需要利用associative机制了(‘associative’机制参考文章)。使用它我们要在.m文件中引入#import <objc/runtime.h>
这里我们主要用到以下两个方法:
-
objc_setAssociatedObject:
// 添加扩展属性 void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy) -
objc_getAssociatedObject
// 获取扩展属性 id objc_getAssociatedObject(id object, void *key)
通过objc_setAssociatedObject方法我们可以为UISlider扩展两个属性来接收传入的target和action。
通过objc_getAssociatedObject方法就可以在接收到UITapGestureRecognizer单击手势时获取target和action,利用[target performSelector:action withObject:self]方法实现单击事件的回调。
下面看下.m中的具体实现:
addTapGestureWithTarget方法为UISlider对象添加UITapGestureRecognizer手势,并为它扩展了三个属性。
1 static char *gestureKey; 2 static char *targetKey; 3 static char *actionStringKey; 4 5 @implementation UISlider (touch) 6 7 - (void)addTapGestureWithTarget:(id)target action:(SEL)action 8 { 9 id gesture = objc_getAssociatedObject(self, &gestureKey); 10 if (!gesture) { 11 objc_setAssociatedObject(self, &targetKey, target, OBJC_ASSOCIATION_ASSIGN); 12 objc_setAssociatedObject(self, &actionStringKey, NSStringFromSelector(action), OBJC_ASSOCIATION_RETAIN); 13 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)]; 14 tap.numberOfTapsRequired = 1; 15 tap.numberOfTouchesRequired = 1; 16 [self addGestureRecognizer:tap]; 17 objc_setAssociatedObject(self, &gestureKey, tap, OBJC_ASSOCIATION_RETAIN); 18 } 19 }
tap:方法中根据点击的位置更新UISlider对象的value,同时从扩展属性中获取target和action回调单击事件。
1 - (void)tap:(UITapGestureRecognizer *)sender 2 { 3 if (sender.state == UIGestureRecognizerStateEnded) { 4 CGPoint location = [sender locationInView:self]; 5 float x = location.x; 6 float r = x/self.frame.size.width; 7 float value = (self.maximumValue-self.minimumValue) * r; 8 [self setValue:value animated:YES]; 9 id target = objc_getAssociatedObject(self, &targetKey); 10 if (target) { 11 NSString *actionStr = objc_getAssociatedObject(self, &actionStringKey); 12 SEL action = NSSelectorFromString(actionStr); 13 [target performSelector:action withObject:self]; 14 } 15 } 16 }
dealloc方法中移除UITapGestureRecognizer
1 - (void)dealloc 2 { 3 UITapGestureRecognizer *tap; 4 id gesture = objc_getAssociatedObject(self, &gestureKey); 5 if (gesture) { 6 tap = (UITapGestureRecognizer*)gesture; 7 [self removeGestureRecognizer:tap]; 8 } 9 } 10 @end
这样我们为UISlider添加单击事件,只需要将Category文件拷入项目import引入就OK了。
下载地址:UISlider+touch.h, UISlider+touch.m
浙公网安备 33010602011771号