UISlider添加单击事件(利用runtime机制)

原生UISlider用作进度条时没有提供单击事件的接口,通过继承在子类中实现单击事件又有杀鸡用牛刀的感觉,于是考虑在Category中实现。

创建UISlider+touch.hUISlider+touch.m文件,添加单击事件方法:

1 @interface UISlider (touch)
2 // 单击手势
3 - (void)addTapGestureWithTarget:(id)target
4                          action:(SEL)action;
5 @end

实现原理是为UISlider对象添加UITapGestureRecognizer,当触发tap事件时利用传入的targetaction回调单击事件。


Category添加方法很简单,但是要扩展属性以保存传入的targetaction两个参数就需要利用associative机制了(‘associative’机制参考文章)。使用它我们要在.m文件中引入#import <objc/runtime.h>

这里我们主要用到以下两个方法:

  1. objc_setAssociatedObject:

     // 添加扩展属性
     void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)   
    
  2. objc_getAssociatedObject

     // 获取扩展属性
     id objc_getAssociatedObject(id object, void *key) 
    

通过objc_setAssociatedObject方法我们可以为UISlider扩展两个属性来接收传入的targetaction

通过objc_getAssociatedObject方法就可以在接收到UITapGestureRecognizer单击手势时获取targetaction,利用[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,同时从扩展属性中获取targetaction回调单击事件。

 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

 

posted @ 2013-04-24 16:18  Azure_Sagi  阅读(952)  评论(0编辑  收藏  举报