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