swift 防止按钮重复点击(时间等候模式/事件完成模式)
关于UIButton重复点击,网上提供了很详细的设置规定时间防止重复点击的方案。但在实际项目中我们常遇到button点击异步网络请求的问题,这时我们不能知晓具体时间时最好能有变量设置判断是否允许点击,很简单的if判断就OK了
//MARK: 防止按钮重复点击
let defaultDuration = 3.0
extension UIButton{
@objc func my_sendAction(action: Selector, to target: AnyObject?, forEvent event: UIEvent?) {
if (self.isKind(of: UIButton.self)) {
switch self.repeatButtonClickType {
case .durationTime:
clickDurationTime = clickDurationTime == 0 ? defaultDuration : clickDurationTime
if isIgnoreEvent {
return
} else if clickDurationTime > 0 {
isIgnoreEvent = true
// 在过了我们设置的duration之后,再将isIgnoreEvent置为false
DispatchQueue.global(qos: .default).asyncAfter(deadline: DispatchTime.now() + clickDurationTime) {
self.isIgnoreEvent = false
}
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + clickDurationTime) {
self.isIgnoreEvent = false
}
my_sendAction(action: action, to: target, forEvent: event)
}
case .enentDone:
if !isFinishEvent {
my_sendAction(action: action, to: target, forEvent: event)
isFinishEvent = true
}
}
} else {
my_sendAction(action: action, to: target, forEvent: event)
}
}
}
enum RepeatButtonClickType : Int{
case durationTime = 0
case enentDone
}
extension UIButton {
private struct AssociatedKeys {
static var clickDurationTime = "my_clickDurationTime"
static var isIgnoreEvent = "my_isIgnoreEvent"
static var isFinish = "my_isFinish"
static var repeatButtonClickType = "repeatButtonClickType"
}
var repeatButtonClickType : RepeatButtonClickType {
set {
objc_setAssociatedObject(self, &AssociatedKeys.repeatButtonClickType, newValue as RepeatButtonClickType, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
if let clickDurationTime = objc_getAssociatedObject(self, &AssociatedKeys.repeatButtonClickType) as? RepeatButtonClickType {
return clickDurationTime
}
return .durationTime
}
}
// 点击间隔时间
var clickDurationTime : TimeInterval {
set {
objc_setAssociatedObject(self, &AssociatedKeys.clickDurationTime, newValue as TimeInterval, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
if let clickDurationTime = objc_getAssociatedObject(self, &AssociatedKeys.clickDurationTime) as? TimeInterval {
return clickDurationTime
}
return defaultDuration
}
}
// 是否忽视点击事件
var isIgnoreEvent : Bool {
set {
objc_setAssociatedObject(self, &AssociatedKeys.isIgnoreEvent, newValue as Bool, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
if let isIgnoreEvent = objc_getAssociatedObject(self, &AssociatedKeys.isIgnoreEvent) as? Bool {
return isIgnoreEvent
}
return false
}
}
// 是否完成点击事件
var isFinishEvent : Bool {
set {
objc_setAssociatedObject(self, &AssociatedKeys.isFinish, newValue as Bool, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
if let isFinishEvent = objc_getAssociatedObject(self, &AssociatedKeys.isFinish) as? Bool {
return isFinishEvent
}
return false
}
}
public class func initializeOnceMethod() {
if self !== UIButton.self {
return
}
DispatchQueue.once(token: "jcgf.swift-Carsh-test-Crash"){
let originalSelector = #selector(UIButton.sendAction)
let swizzledSelector = #selector(UIButton.my_sendAction(action:to:forEvent:))
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
// 运行时为类添加我们自己写的my_sendAction(_:to:forEvent:)
let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
if didAddMethod {
// 如果添加成功,则交换方法
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
} else {
// 如果添加失败,则交换方法的具体实现
method_exchangeImplementations(originalMethod!, swizzledMethod!)
}
}
}
}
extension DispatchQueue {
private static var _onceTracker = "Stringss"
public class func once(token: String, block: () -> ()) {
objc_sync_enter(self)
defer {
objc_sync_exit(self)
}
if _onceTracker.contains(token) {
return
}
_onceTracker.append(token)
block()
}
func async(block: @escaping ()->()) {
self.async(execute: block)
}
func after(time: DispatchTime, block: @escaping ()->()) {
self.asyncAfter(deadline: time, execute: block)
}
}
使用示例:
override func viewDidLoad() {
super.viewDidLoad()
button = UIButton.init(type: .custom)
button?.frame = CGRect(x: 0, y: 500, width: 200, height: 50)
button?.setTitleColor(.red, for: .normal)
button?.setTitle("haha", for: .normal)
view.addSubview(button!)
button?.addTarget(self, action: #selector(buttonClick), for: UIControlEvents.touchUpInside)
UIButton.initializeOnceMethod()
//默认是3秒内不能重复点击,加入下面代码则表示进入等待点击事件执行到输出isFinishEvent = false
button?.repeatButtonClickType = .enentDone
}
@objc func buttonClick() {
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 10) {
self.button?.isFinishEvent = false
}
print("55667")
}
网友评论