jsdw_ios/QuickLocation/Core/Extension/ControlEvents+Block.swift

231 lines
7.3 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Block.swift
// DLSDK
//
// Created by osell on 2023/3/6.
//
import UIKit
import ObjectiveC.runtime
public typealias VoidAnyBlock = (Any) -> Void
class InnerBlockTarget: NSObject {
var identifier: String = ""
var block: VoidAnyBlock?
var events: UIControl.Event?
override init() {
self.identifier = UUID().uuidString
super.init()
}
@objc
func invoke(_ sender: Any) {
if let block = block {
block(sender)
}
}
}
// MARK: - UIGestureRecognizer + Block
@objc extension UIGestureRecognizer {
struct BlockKey {
static var innerBlockTargets = "innerBlockTargets"
}
var innerBlockTargets: [InnerBlockTarget] {
get {
guard let targets = objc_getAssociatedObject(self, &BlockKey.innerBlockTargets) as? [InnerBlockTarget] else {
return []
}
return targets
}
set {
objc_setAssociatedObject(self, &BlockKey.innerBlockTargets, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
/// 增加Tap
/// - Parameter block: 事件回调
/// - Returns: UIGestureRecognizer
@discardableResult
public class func gestureRecognizer(with block: @escaping VoidAnyBlock) -> UIGestureRecognizer {
let gestureRecognizer = UIGestureRecognizer()
gestureRecognizer.addBlock(block)
return gestureRecognizer
}
/// 增加Block
@discardableResult
public func addBlock(_ block: @escaping VoidAnyBlock) -> String {
let target = InnerBlockTarget()
target.block = block
addTarget(target, action: #selector(InnerBlockTarget.invoke(_:)))
var targets = innerBlockTargets
targets.append(target)
innerBlockTargets = targets
return target.identifier
}
/// 删除Block
public func removeBlock(identifier: String) {
if identifier.isEmpty { return }
var targets = innerBlockTargets
guard let target = targets.first(where: { $0.identifier == identifier }) else { return }
removeTarget(target, action: #selector(InnerBlockTarget.invoke(_:)))
targets.removeObject(target)
innerBlockTargets = targets
}
/// 删除全部
public func removeAll() {
innerBlockTargets.forEach {
self.removeTarget($0, action: #selector(InnerBlockTarget.invoke(_:)))
}
innerBlockTargets = []
}
}
// MARK: - UIView + Block
@objc extension UIView {
struct BlockKey {
static var addTapGestrueBlock = "addTapGestrueBlock"
}
/// UIView添加Tap点击事件
/// - Parameters:
/// - taget: Any
/// - action: Selector
public func addTapGestrue(with taget: Any, action: Selector?) {
let tap = UITapGestureRecognizer(target: taget, action: action)
isUserInteractionEnabled = true
addGestureRecognizer(tap)
}
/// UIView添加Tap点击事件
/// - Parameter block: 点击Block回调
/// - Returns: indetifier
@discardableResult
public func addTapGestrue(block: @escaping VoidAnyBlock) -> String {
let tap = UITapGestureRecognizer()
let indetifier = tap.addBlock(block)
objc_setAssociatedObject(tap, &BlockKey.addTapGestrueBlock, indetifier, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
isUserInteractionEnabled = true
addGestureRecognizer(tap)
return indetifier
}
/// 移除Tap事件
/// - Parameter identifier: identifier
public func removeTapGestrueBlock(with identifier: String) {
if identifier.isEmpty { return }
gestureRecognizers?.forEach {
if $0.isKind(of: UITapGestureRecognizer.self),
let tempidentifier = objc_getAssociatedObject($0, &BlockKey.addTapGestrueBlock) as? String,
tempidentifier == identifier {
$0.removeBlock(identifier: identifier)
self.removeGestureRecognizer($0)
}
}
}
}
// MARK: - UIControl + Block
@objc extension UIControl {
struct BlockKey {
static var innerBlockTargets = "innerBlockTargets"
}
var innerBlockTargets: [InnerBlockTarget] {
get {
guard let targets = objc_getAssociatedObject(self, &BlockKey.innerBlockTargets) as? [InnerBlockTarget] else {
return []
}
return targets
}
set {
objc_setAssociatedObject(self, &BlockKey.innerBlockTargets, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
/// 添加block的ControlEvents
/// - Parameters:
/// - controlEvents: UIControl.Event
/// - block: (Any) -> Void
/// - Returns: identifier
@discardableResult
public func addBlock(for controlEvents: UIControl.Event,
block: @escaping VoidAnyBlock) -> String {
if let target = innerBlockTargets.first(where: { $0.events == controlEvents }) {
innerBlockTargets.removeObject(target)
}
let target = InnerBlockTarget()
target.block = block
target.events = controlEvents
addTarget(target, action: #selector(InnerBlockTarget.invoke(_:)), for: controlEvents)
var targets = innerBlockTargets
targets.append(target)
innerBlockTargets = targets
return target.identifier
}
/// 移除Block
/// - Parameters:
/// - controlEvents: UIControl.Event
/// - identifier: identifier
public func removeBlock(for controlEvents: UIControl.Event, identifier: String) {
if identifier.isEmpty { return }
removeAllBlock(for: controlEvents, identifier: identifier)
}
/// 移除identifier全部Block
/// - Parameters:
/// - controlEvents: UIControl.Event
/// - identifier: identifier, 默认为空,会移除所有的block
public func removeAllBlock(for controlEvents: UIControl.Event, identifier: String = "") {
var targets = innerBlockTargets
var removes = [InnerBlockTarget]()
targets.forEach {
if let events = $0.events,
((events.rawValue & controlEvents.rawValue) != 0),
($0.identifier == identifier || identifier.isEmpty) {
let event = UIControl.Event(rawValue: events.rawValue & (~controlEvents.rawValue))
if event.rawValue != 0 {
removeTarget($0, action: #selector(InnerBlockTarget.invoke(_:)), for: controlEvents)
$0.events = event
addTarget($0, action: #selector(InnerBlockTarget.invoke(_:)), for: event)
} else {
removeTarget($0, action: #selector(InnerBlockTarget.invoke(_:)), for: controlEvents)
removes.append($0)
}
}
}
removes.forEach {
targets.removeObject($0)
}
innerBlockTargets = targets
}
public func addTouchTarget(_ target: Any, action: Selector) {
addTarget(target, action: action, for: .touchUpInside)
}
@discardableResult
public func addTouchBlock(_ block: @escaping VoidAnyBlock) -> String {
addBlock(for: .touchUpInside, block: block)
}
public func removeTouchBlock(with identifier: String) {
removeBlock(for: .touchUpInside, identifier: identifier)
}
}