What is Tap Gesture:
If you’ve ever used an iOS device, then, whether you know it or not, you’ve used tap gesture recognition on many occasions. like double tapping functionality, add action to non-clickable view objects etc. All of these actions are done by tap gesture recognizers.
Disadvantage:
The worst part about adding a UITapGestureRecognizer
or any sort of gesture recognizer/target action is implementing a new function solely for the selector parameter. For this, I’d like to share a neat trick I threw together that lets you add gesture recognizers without selectors.
Implementation:
Let’s say we have anUIImageView
in our View Controller and we want to add a UITapGestureRecognizer
to it that prints out a statement whenever it’s tapped.
Normally we would create an instance of a UITapGestureRecognizer
and set a target to the View Controller and its selector as some function we quickly threw together (myImageViewTapped(sender: UITapGestureRecognizer)
). This can get a bit redundant and can lead to messy code with functions for every subview you want to add interactivity too.
I got to thinking that I could just make a quick extension that adds tap gesture recognizers to my image view for me, but then I’d have to make a new function for each recognizer, right? Wrong! Using the power of associated objects, we can actually store closures as computed properties in our extension!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
extension UIView { fileprivate struct AssociatedObjectKeys { static var tapGestureRecognizer = "MyAssociatedObjectKeyForTapGesture" } fileprivate typealias Action = (() -> Void)? fileprivate var tapGestureRecognizerAction: Action? { set { if let newValue = newValue { objc_setAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) } } get { let tapGestureRecognizerActionInstance = objc_getAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer) as? Action return tapGestureRecognizerActionInstance } } public func addTapGestureRecognizer(action: (() -> Void)?) { self.isUserInteractionEnabled = true self.tapGestureRecognizerAction = action let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture)) self.addGestureRecognizer(tapGestureRecognizer) } @objc fileprivate func handleTapGesture(sender: UITapGestureRecognizer) { if let action = self.tapGestureRecognizerAction { action?() } else { print("no action") } } } |
Uses:
1 2 3 4 5 6 7 |
override func viewDidLoad() { super.viewDidLoad() myImageView.addTapGestureRecognizer { print("Image tapped") } } |
Thank You!!!