開頭
在開始還是來扯點(diǎn)其他的.下午睡覺睡到五六點(diǎn)鐘,然后去附近的學(xué)校小跑了會(huì).由于學(xué)校距離公司很近,順便就到公司搗鼓搗鼓代碼.反正閑著也是閑著.
今天的重點(diǎn)
今天重點(diǎn)在于通過runtime來為button添加一些類似快捷設(shè)置的功能.其實(shí)就是為類添加新的屬性.技術(shù)含量確實(shí)不是很高.網(wǎng)上都把這個(gè)寫泛濫了.里面有一些注釋不同于其他的在于我是用英文注釋的(在這里裝個(gè)逼,O(∩_∩)O~)
具體功能點(diǎn)
設(shè)置button在一定時(shí)間間隔內(nèi)不能再次點(diǎn)擊.
這個(gè)功能其實(shí)在項(xiàng)目中也是比較常見的.舉個(gè)例子,當(dāng)你的項(xiàng)目運(yùn)行不是很流暢的時(shí)候(通常出現(xiàn)在比較大的項(xiàng)目中),連續(xù)點(diǎn)擊會(huì)觸發(fā)多次事件,造成比如多次請(qǐng)求網(wǎng)絡(luò),多次push等.button快速設(shè)置不同狀態(tài)下的背景顏色(button設(shè)置背景顏色不是根據(jù)狀態(tài)的哦)
快速添加block代替addTarget,其實(shí)就是著名的(blockkit)里面早就做了.
先來看看效果吧
中間其實(shí)是一個(gè)button,這里設(shè)置的是3秒之后才能觸發(fā)點(diǎn)擊事件.
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:btn];
btn.frame = CGRectMake(0, 0, 40, 40);
[btn centerToParentNoScale];
btn.backgroundColor = [UIColor greenColor];
[btn setBackgroundColor:[UIColor greenColor] forState:UIControlStateNormal];
[btn setBackgroundColor:[UIColor redColor] forState:UIControlStateHighlighted];
btn.timeInterval = 3.0;
[btn addActionHandler:^(NSInteger tag) {
self.view.backgroundColor = RandomColor;
}];
詳細(xì)代碼(為了做成工具,功能點(diǎn)寫在一個(gè)分類里面)
.h文件
#import <UIKit/UIKit.h>
typedef void (^TouchedBlock)(NSInteger tag);
@interface UIButton (XLKit)
/**
* Click on the button how much time interval is not responding
*/
@property (nonatomic, assign) NSTimeInterval timeInterval;
/**
* With the background color of different color Settings button state (the default background color is not change with state)
*/
- (void)setBackgroundColor:(UIColor *)backgroundColor
forState:(UIControlState)state;
/**
* Add block repalce addtarget
*/
- (void)addActionHandler:(TouchedBlock)touchHandler;
@end
.m文件
@interface UIButton ()
/**
* Is to ignore the button Touch Event
*/
@property (nonatomic, assign) BOOL isIgnoreTouch;
@end
@implementation UIButton (XLKit)
#pragma mark -
#pragma mark - TouchInterval
- (NSTimeInterval)timeInterval {
return [objc_getAssociatedObject(self, _cmd) doubleValue];
}
- (void)setTimeInterval:(NSTimeInterval) timeInterval {
objc_setAssociatedObject(self, @selector(timeInterval), @(timeInterval), OBJC_ASSOCIATION_ASSIGN);
}
- (BOOL)isIgnoreTouch {
// _cmd == @selector(isIgnoreTouch)
return [objc_getAssociatedObject(self, _cmd) boolValue];
}
- (void)setIsIgnoreTouch:(BOOL)isIgnoreTouch {
objc_setAssociatedObject(self, @selector(isIgnoreTouch), @(isIgnoreTouch), OBJC_ASSOCIATION_ASSIGN);
}
#pragma mark - Load & Swilling
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL orginSEL = @selector(sendAction:to:forEvent:);
SEL newSEL = @selector(newSendAction:to:forEvent:);
Method orginMethod = class_getInstanceMethod(self, orginSEL);
Method newMethod = class_getInstanceMethod(self, newSEL);
// The realization of the newMethod is added to the system method That is to say, Add orginMethod method Pointers into method newMethod return value indicates whether or not to add a success
BOOL isAdd = class_addMethod(self, orginSEL, method_getImplementation(newMethod), method_getTypeEncoding(newMethod));
// Add a success So at this moment does not exist in this class that newMethod methods must be newMethod orginMethod pointer into method, otherwise the newMethod method will not be implemented.
if (isAdd) {
class_replaceMethod(self, newSEL, method_getImplementation(orginMethod), method_getTypeEncoding(orginMethod));
}else{
// If add failed With the realization of the newMethod in this class, now just need to orginMethod and newMethod IMP exchange.
method_exchangeImplementations(orginMethod, newMethod);
}
});
}
// When click on the button event sendAction will perform newSendAction
- (void)newSendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
if ([self isKindOfClass:[UIButton class]]) {
if (!self.isIgnoreTouch) {
self.timeInterval = self.timeInterval == 0 ? 0:self.timeInterval;
};
if (self.isIgnoreTouch) {
return;
}
if (self.timeInterval > 0) {
self.isIgnoreTouch = YES;
// Note this is perform on the current thread using the default mode after a delay.
[self performSelector:@selector(setIsIgnoreTouch:)
withObject:nil
afterDelay:self.timeInterval];
}
}
[self newSendAction:action to:target forEvent:event];
}
#pragma mark -
#pragma mark - BackgroudColor
- (void)setBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state {
[self setBackgroundImage:[UIButton imageWithColor:backgroundColor] forState:state];
}
+ (UIImage *)imageWithColor:(UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
#pragma mark -
#pragma mark - Block repalce AddTarget
-(void)addActionHandler:(TouchedBlock)touchHandler {
objc_setAssociatedObject(self, @selector(actionTouched:), touchHandler, OBJC_ASSOCIATION_COPY_NONATOMIC);
[self addTarget:self action:@selector(actionTouched:) forControlEvents:UIControlEventTouchUpInside];
}
-(void)actionTouched:(UIButton *)btn {
TouchedBlock block = objc_getAssociatedObject(self, _cmd);
if (block) {
block(btn.tag);
}
}
@end
后記
該回去了,代碼就差不多如上所示.注釋使用英文寫的(只為裝逼,大神似乎都是這樣哦!).
建議看看Swilling(方法交換)的具體實(shí)現(xiàn).如Method,IMP,SEL.三者之間的關(guān)系.因?yàn)槲颐嬖囘^好多人,幾乎都不知道.O(∩_∩)O~.
玩得愉快