Skip to content

Instantly share code, notes, and snippets.

@JohnCoates
Created May 18, 2017 09:14
Show Gist options
  • Save JohnCoates/2b6892b023a3f93092ab395cb8b743c9 to your computer and use it in GitHub Desktop.
Save JohnCoates/2b6892b023a3f93092ab395cb8b743c9 to your computer and use it in GitHub Desktop.
UIGestureRecognizer with closure, Swift 3
import UIKit
extension UIGestureRecognizer {
@discardableResult convenience init(addToView targetView: UIView,
closure: @escaping () -> Void) {
self.init()
GestureTarget.add(gesture: self,
closure: closure,
toView: targetView)
}
}
fileprivate class GestureTarget: UIView {
class ClosureContainer {
weak var gesture: UIGestureRecognizer?
let closure: (() -> Void)
init(closure: @escaping () -> Void) {
self.closure = closure
}
}
var containers = [ClosureContainer]()
convenience init() {
self.init(frame: .zero)
isHidden = true
}
class func add(gesture: UIGestureRecognizer, closure: @escaping () -> Void,
toView targetView: UIView) {
let target: GestureTarget
if let existingTarget = existingTarget(inTargetView: targetView) {
target = existingTarget
} else {
target = GestureTarget()
targetView.addSubview(target)
}
let container = ClosureContainer(closure: closure)
container.gesture = gesture
target.containers.append(container)
gesture.addTarget(target, action: #selector(GestureTarget.target(gesture:)))
targetView.addGestureRecognizer(gesture)
}
class func existingTarget(inTargetView targetView: UIView) -> GestureTarget? {
for subview in targetView.subviews {
if let target = subview as? GestureTarget {
return target
}
}
return nil
}
func cleanUpContainers() {
containers = containers.filter({ $0.gesture != nil })
}
@objc func target(gesture: UIGestureRecognizer) {
cleanUpContainers()
for container in containers {
guard let containerGesture = container.gesture else {
continue
}
if gesture === containerGesture {
container.closure()
}
}
}
}
@JohnCoates
Copy link
Author

JohnCoates commented May 18, 2017

use like this:

    UITapGestureRecognizer(addToView: targetView) { 
            print("preview tapped!")
        }

GestureTarget adds itself as a subview of the target view so that its lifecycle is tied to it, and the closure gets deallocated once it's no longer used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment