How to add a touch event to a UIView?
Solution 1
In iOS 3.2 and higher, you can use gesture recognizers. For example, this is how you would handle a tap event:
//The setup code (in viewDidLoad in your view controller)
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];
//The event handling method
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
CGPoint location = [recognizer locationInView:[recognizer.view superview]];
//Do stuff here...
}
There are a bunch of built in gestures as well. Check out the docs for iOS event handling and UIGestureRecognizer
. I also have a bunch of sample code up on github that might help.
Solution 2
Gesture Recognizers
There are a number of commonly used touch events (or gestures) that you can be notified of when you add a Gesture Recognizer to your view. They following gesture types are supported by default:
-
UITapGestureRecognizer
Tap (touching the screen briefly one or more times) -
UILongPressGestureRecognizer
Long touch (touching the screen for a long time) -
UIPanGestureRecognizer
Pan (moving your finger across the screen) -
UISwipeGestureRecognizer
Swipe (moving finger quickly) -
UIPinchGestureRecognizer
Pinch (moving two fingers together or apart - usually to zoom) -
UIRotationGestureRecognizer
Rotate (moving two fingers in a circular direction)
In addition to these, you can also make your own custom gesture recognizer.
Adding a Gesture in the Interface Builder
Drag a gesture recognizer from the object library onto your view.
Control drag from the gesture in the Document Outline to your View Controller code in order to make an Outlet and an Action.
This should be set by default, but also make sure that User Action Enabled is set to true for your view.
Adding a Gesture Programmatically
To add a gesture programmatically, you (1) create a gesture recognizer, (2) add it to a view, and (3) make a method that is called when the gesture is recognized.
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// 1. create a gesture recognizer (tap gesture)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))
// 2. add the gesture recognizer to a view
myView.addGestureRecognizer(tapGesture)
}
// 3. this method is called when a tap is recognized
@objc func handleTap(sender: UITapGestureRecognizer) {
print("tap")
}
}
Notes
- The
sender
parameter is optional. If you don't need a reference to the gesture then you can leave it out. If you do so, though, remove the(sender:)
after the action method name. - The naming of the
handleTap
method was arbitrary. Name it whatever you want usingaction: #selector(someMethodName(sender:))
.
More Examples
You can study the gesture recognizers that I added to these views to see how they work.
Here is the code for that project:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var tapView: UIView!
@IBOutlet weak var doubleTapView: UIView!
@IBOutlet weak var longPressView: UIView!
@IBOutlet weak var panView: UIView!
@IBOutlet weak var swipeView: UIView!
@IBOutlet weak var pinchView: UIView!
@IBOutlet weak var rotateView: UIView!
@IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Tap
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
tapView.addGestureRecognizer(tapGesture)
// Double Tap
let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
doubleTapView.addGestureRecognizer(doubleTapGesture)
// Long Press
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(gesture:)))
longPressView.addGestureRecognizer(longPressGesture)
// Pan
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(gesture:)))
panView.addGestureRecognizer(panGesture)
// Swipe (right and left)
let swipeRightGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(gesture:)))
let swipeLeftGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(gesture:)))
swipeRightGesture.direction = UISwipeGestureRecognizerDirection.right
swipeLeftGesture.direction = UISwipeGestureRecognizerDirection.left
swipeView.addGestureRecognizer(swipeRightGesture)
swipeView.addGestureRecognizer(swipeLeftGesture)
// Pinch
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(gesture:)))
pinchView.addGestureRecognizer(pinchGesture)
// Rotate
let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(handleRotate(gesture:)))
rotateView.addGestureRecognizer(rotateGesture)
}
// Tap action
@objc func handleTap() {
label.text = "Tap recognized"
// example task: change background color
if tapView.backgroundColor == UIColor.blue {
tapView.backgroundColor = UIColor.red
} else {
tapView.backgroundColor = UIColor.blue
}
}
// Double tap action
@objc func handleDoubleTap() {
label.text = "Double tap recognized"
// example task: change background color
if doubleTapView.backgroundColor == UIColor.yellow {
doubleTapView.backgroundColor = UIColor.green
} else {
doubleTapView.backgroundColor = UIColor.yellow
}
}
// Long press action
@objc func handleLongPress(gesture: UILongPressGestureRecognizer) {
label.text = "Long press recognized"
// example task: show an alert
if gesture.state == UIGestureRecognizerState.began {
let alert = UIAlertController(title: "Long Press", message: "Can I help you?", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
// Pan action
@objc func handlePan(gesture: UIPanGestureRecognizer) {
label.text = "Pan recognized"
// example task: drag view
let location = gesture.location(in: view) // root view
panView.center = location
}
// Swipe action
@objc func handleSwipe(gesture: UISwipeGestureRecognizer) {
label.text = "Swipe recognized"
// example task: animate view off screen
let originalLocation = swipeView.center
if gesture.direction == UISwipeGestureRecognizerDirection.right {
UIView.animate(withDuration: 0.5, animations: {
self.swipeView.center.x += self.view.bounds.width
}, completion: { (value: Bool) in
self.swipeView.center = originalLocation
})
} else if gesture.direction == UISwipeGestureRecognizerDirection.left {
UIView.animate(withDuration: 0.5, animations: {
self.swipeView.center.x -= self.view.bounds.width
}, completion: { (value: Bool) in
self.swipeView.center = originalLocation
})
}
}
// Pinch action
@objc func handlePinch(gesture: UIPinchGestureRecognizer) {
label.text = "Pinch recognized"
if gesture.state == UIGestureRecognizerState.changed {
let transform = CGAffineTransform(scaleX: gesture.scale, y: gesture.scale)
pinchView.transform = transform
}
}
// Rotate action
@objc func handleRotate(gesture: UIRotationGestureRecognizer) {
label.text = "Rotate recognized"
if gesture.state == UIGestureRecognizerState.changed {
let transform = CGAffineTransform(rotationAngle: gesture.rotation)
rotateView.transform = transform
}
}
}
Notes
- You can add multiple gesture recognizers to a single view. For the sake of simplicity, though, I didn't do that (except for the swipe gesture). If you need to for your project, you should read the gesture recognizer documentation. It is fairly understandable and helpful.
- Known issues with my examples above: (1) Pan view resets its frame on next gesture event. (2) Swipe view comes from the wrong direction on the first swipe. (These bugs in my examples should not affect your understanding of how Gestures Recognizers work, though.)
Solution 3
I think you can simply use
UIControl *headerView = ...
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];
i mean headerView extends from UIControl.
Solution 4
Swift 3 & Swift 4
import UIKit
extension UIView {
func addTapGesture(tapNumber: Int, target: Any, action: Selector) {
let tap = UITapGestureRecognizer(target: target, action: action)
tap.numberOfTapsRequired = tapNumber
addGestureRecognizer(tap)
isUserInteractionEnabled = true
}
}
Use
yourView.addTapGesture(tapNumber: 1, target: self, action: #selector(yourMethod))
Solution 5
Based on the accepted answer you can define a macro:
#define handle_tap(view, delegate, selector) do {\
view.userInteractionEnabled = YES;\
[view addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget:delegate action:selector]];\
} while(0)
This macro uses ARC, so there's no release
call.
Macro usage example:
handle_tap(userpic, self, @selector(onTapUserpic:));
Related videos on Youtube
Comments
-
Manni over 2 years
How do I add a touch event to a UIView?
I try:UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, nextY)] autorelease]; [headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown]; // ERROR MESSAGE: UIView may not respond to '-addTarget:action:forControlEvents:'
I don't want to create a subclass and overwrite
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
-
Mr.Javed Multani about 6 yearsFor swift you can get it from here: stackoverflow.com/questions/28675209/…
-
-
M Penades almost 13 yearsBut that is overwriting touch defautlt action of the view. ¿Is it possible to call default touch action of the view? Something like [super touchesBegan] ?...
-
zakdances about 12 yearsWhat does the CGPoint line do?
-
Nathan Eror about 12 years@yourfriendzak the
CGPoint
represents the location of the tap in the superview of the tapped view. You can use this point to move the tapped view (or a sibling view) to the tapped location. This is more useful in the handler for aUIPanGestureRecognizer
for dragging the view around the screen. -
natbro about 12 yearsgreat concise answer, thanks. but sheesh, wouldn't it be nice if this were a wee bit easier?! :)
-
Nathan Eror about 12 yearsIt's not too bad, but I wish there were a block based API like github.com/neror/ftutils/blob/master/Headers/FTUtils/…. Xcode 4 does have support for adding/configuring gesture recognizers in Interface Builder, too.
-
David T. almost 12 yearsI got most of this to work; however, why is it that when i print the coordinates using NSLog(@"touched points: %f, %f", location.x, location.y); i always get 0.00000, 0.00000 ??? is it because of my simulator? i'm using my trackpad on my mac pro
-
meadlai over 11 years@NathanEror UIView only can add ONE GestureRecognizer. I try to handle more than one EventHandler. gist.github.com/1450404
-
ohho over 11 yearsThis is the better answer.
UITapGestureRecognizer
is not a replacement ofUIControlEventTouchDown
. ATap
usually composes ofUIControlEventTouchDown
andUIControlEventTouchUpInside
. -
RobertJoseph over 11 yearsA
UIView
is not aUIControl
and thus does not have access toaddTarget:action:forControlEvents:
. -
pretzels1337 over 11 yearsAlso note that a UIControl inherits from UIView. For my purposes all I had to do was a simple switch of subclass type.
-
david over 10 yearsIf you create the view in storyboard, don't forget to enable the "user interaction enabled" option.
-
Zar E Ahmer over 9 yearsyou can set its class to UIControl @RobertJoseph .. Go to xib file and set the View Custom class to UIControl . now you can handle event in it..
-
Zar E Ahmer over 9 yearswhere we should define macros in .h or .m and what should be the name of the parameters . i mean #define handle_tap(UIView view,Delegate delegate , SEL selector)do..
-
Anthony Glyadchenko over 9 yearsSo why this a better solution again since I'm changing inheritance just to handle taps?
-
Moin Shirazi over 8 yearsi am having multiple view so can i can the sender id ??
-
Programming Learner over 8 yearsYou have to go to the inner subview, then you can paas the sender.---------for (UIView *view in self.topicScrollView.subviews) {//Go Inside the superview if ([view isKindOfClass:[UIButton class]]) { // Go to that particular view // Here you have reached upto that point. } }
-
dollar2048 about 8 yearsyou have to add view.userInteractionEnabled = YES;
-
He Yifei 何一非 over 7 yearswhat is
BlockTap
? -
Esqarrouth over 7 yearsOh man, forgot that part. Its a custom function. Here: github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/…
-
Er. Vihar about 7 yearsYour answer is really nice and helpful with detailed description. And thats why I have up vote you answer also. But you just missed one instruction which I think you must include in your answer as you have explained it in full detail. That instruction is about setting "<yourView>.EnableUserInteraction = TRUE". I hope you agree with me.
-
sebesbal almost 7 yearsThere is a difference between a single tap, and a touch event, with multiple pointers and down/move/up states. Almost each of the answers talks about single tap...
-
Mikrasya almost 6 yearsThanks. Works great!
-
budiDino almost 6 yearsLove this! Adding to all of the projects ;)
-
neiker almost 6 yearsIn order to make this work on a
UIView
you need to also add:self.isUserInteractionEnabled = true;
-
janakmshah about 4 years@AnthonyGlyadchenko this is a better answer because the original question asks: How do I add a touch event to a UIView? It isn't asking for a tap event. Specifically OP wants to implement
UIControlEventTouchDown
. Switching the UIView to UIControl is the right answer because Gesture Recognisers don't know anything about.touchDown
,.touchUpInside
,.touchUpOutside
etc. -
Muhammad Ahmed over 3 yearsI have view in which i have implemented DropMenu whenever a view is tapped. i am getting an error "Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value" at myView.addGestureRecognizer(tapGesture) when ever i go to next screen