iOS Button连按处理防止按钮连续点击

简介: iOS Button连按处理防止按钮连续点击

前言


需求介绍:很多时候我们不希望按钮多次连按,如果去写Enabled略显麻烦,这里提供一种控制按钮点击间隔时间的方法,我已封装方便使用


GitHub地址:KJCategories


API


/* ******************这两个属性互斥********************/
/// 接受点击事件的时间间隔
@property (nonatomic, assign) NSTimeInterval kj_AcceptEventTime;
/// 接受点击事件执行处理之后的时间间隔
@property (nonatomic, assign) NSTimeInterval kj_AcceptDealTime;
/* ******************这两个属性互斥********************/


Runtime方法交换


内部以Category的方式实现,考虑到侵入性问题,所以没有将方法交换放在load里面,而是选择以委托(KJButtonTimeExchangeMethodProtocol)的形式,内部采用 dispatch_once 的方式保证只调用一次

@protocol KJButtonTimeExchangeMethodProtocol <NSObject>
@required
/// 是否开启时间间隔的方法交换
+ (void)kj_openTimeExchangeMethod;
@end

可以选择在任何你要使用属性kj_AcceptEventTimekj_AcceptDealTime 之前调用即可,例如viewDidLoad

[UIButton kj_openTimeExchangeMethod];

其实就是交换方法 sendAction:to:forEvent:,在 kj_sendAction:to:forEvent: 当中判断时间间隔

/// 交换方法后实现
- (void)kj_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{
    if (self.kj_AcceptEventTime <= 0 && self.kj_AcceptDealTime <= 0) {
        [self kj_sendAction:action to:target forEvent:event];
        return;
    }
    NSTimeInterval time = self.kj_AcceptEventTime > 0 ? self.kj_AcceptEventTime : self.kj_AcceptDealTime;
    BOOL boo = (CFAbsoluteTimeGetCurrent() - self.kLastTime >= time);
    if (self.kj_AcceptEventTime > 0) {
        self.kLastTime = CFAbsoluteTimeGetCurrent();
    }
    if (boo) {
        if (self.kj_AcceptDealTime > 0) {
            self.kLastTime = CFAbsoluteTimeGetCurrent();
        }
        [self kj_sendAction:action to:target forEvent:event];
    }
}
如不需要点击事件间隔处理了,只需要将 kj_AcceptEventTimekj_AcceptDealTime 两个属性值设置为非正数即可


实现


//
//  UIButton+KJBlock.m
//  KJEmitterView
//
//  Created by 杨科军 on 2019/4/4.
//  Copyright © 2019 杨科军. All rights reserved.
//  https://github.com/yangKJ/KJExtensionHandler
#import "UIButton+KJBlock.h"
#import <objc/runtime.h>
@implementation UIButton (KJBlock)
static char kParameterTag;
/// 添加点击事件,默认UIControlEventTouchUpInside
- (void)kj_addAction:(KJButtonBlock)block{
    objc_setAssociatedObject(self, &kParameterTag, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
}
/// 添加事件
- (void)kj_addAction:(KJButtonBlock)block forControlEvents:(UIControlEvents)controlEvents{
    objc_setAssociatedObject(self, &kParameterTag, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self addTarget:self action:@selector(action:) forControlEvents:controlEvents];
}
/// 事件响应方法
- (void)action:(UIButton*)sender{
    KJButtonBlock block = objc_getAssociatedObject(self, &kParameterTag);
    if (block) block(self);
}
#pragma mark - 时间相关方法交换
/// 是否开启时间间隔的方法交换
+ (void)kj_openTimeExchangeMethod{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL originalSelector = @selector(sendAction:to:forEvent:);
        SEL swizzledSelector = @selector(kj_sendAction:to:forEvent:);
        Class clazz = [self class];
        Method originalMethod = class_getInstanceMethod(clazz, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(clazz, swizzledSelector);
        BOOL boo = class_addMethod(clazz, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
        if (boo) {
            class_replaceMethod(clazz, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        }else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}
/// 交换方法后实现
- (void)kj_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{
    if (self.kj_AcceptEventTime <= 0 && self.kj_AcceptDealTime <= 0) {
        [self kj_sendAction:action to:target forEvent:event];
        return;
    }
    NSTimeInterval time = self.kj_AcceptEventTime > 0 ? self.kj_AcceptEventTime : self.kj_AcceptDealTime;
    BOOL boo = (CFAbsoluteTimeGetCurrent() - self.kLastTime >= time);
    if (self.kj_AcceptEventTime > 0) {
        self.kLastTime = CFAbsoluteTimeGetCurrent();
    }
    if (boo) {
        if (self.kj_AcceptDealTime > 0) {
            self.kLastTime = CFAbsoluteTimeGetCurrent();
        }
        [self kj_sendAction:action to:target forEvent:event];
    }
}
- (NSTimeInterval)kj_AcceptEventTime{
    return [objc_getAssociatedObject(self, @selector(kj_AcceptEventTime)) doubleValue];
}
- (void)setKj_AcceptEventTime:(NSTimeInterval)kj_AcceptEventTime{
    objc_setAssociatedObject(self, @selector(kj_AcceptEventTime), @(kj_AcceptEventTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSTimeInterval)kj_AcceptDealTime{
    return [objc_getAssociatedObject(self, @selector(kj_AcceptDealTime)) doubleValue];
}
- (void)setKj_AcceptDealTime:(NSTimeInterval)kj_AcceptDealTime{
    objc_setAssociatedObject(self, @selector(kj_AcceptDealTime), @(kj_AcceptDealTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSTimeInterval)kLastTime{
    return [objc_getAssociatedObject(self, @selector(kLastTime)) doubleValue];
}
- (void)setKLastTime:(NSTimeInterval)kLastTime{
    objc_setAssociatedObject(self, @selector(kLastTime), @(kLastTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

粗略封装,望大神帮助修改完善


备注:本文用到的部分函数方法和Demo,均来自三方库**KJCategories**,如有需要的朋友可自行pod 'KJCategories'引入即可


Button处理介绍就到此完毕,后面有相关再补充,写文章不容易,还请点个**小星星**传送门

相关文章
|
iOS开发
iOS MFMessageComposeViewController不显示取消按钮,导航条上白色,无取消按钮,无法返回应用...
iOS MFMessageComposeViewController不显示取消按钮,导航条上白色,无取消按钮,无法返回应用...
70 0
|
3月前
|
iOS开发
iOS超出父控件范围无法点击问题
iOS超出父控件范围无法点击问题
143 58
|
28天前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户点击按钮时,按钮将从圆形变为椭圆形,颜色从蓝色渐变到绿色;释放按钮时,动画以相反方式恢复。通过UIView的动画方法和弹簧动画效果,实现平滑自然的过渡。
50 1
|
2月前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
【10月更文挑战第18天】本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户按下按钮时,按钮将从圆形变为椭圆形并从蓝色渐变为绿色;释放按钮时,动画恢复原状。通过UIView的动画方法和弹簧动画效果,实现平滑自然的动画过渡。
52 5
|
3月前
|
iOS开发
iOS超出父控件范围无法点击问题
iOS超出父控件范围无法点击问题
|
7月前
|
iOS开发
iOS13.6.1系统XR手机图文按钮显示不全问题
iOS13.6.1系统XR手机图文按钮显示不全问题
71 0
|
7月前
按钮的image图片是非圆角,直接对UIButton设置圆角,iOS13系统没有圆角效果的问题及解决方案
按钮的image图片是非圆角,直接对UIButton设置圆角,iOS13系统没有圆角效果的问题及解决方案
50 0
vue--ios手机input点击手机输入键盘顶起页面解决方案
vue--ios手机input点击手机输入键盘顶起页面解决方案
|
iOS开发 设计模式
|
11天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。