59
votes

I'm new to gesture recognizers so maybe this question sounds silly: I'm assigning tap gesture recognizers to a bunch of UIViews. In the method is it possible to find out which of them was tapped somehow or do I need to find it out using the point that was tapped on screen?

for (NSUInteger i=0; i<42; i++) {
        float xMultiplier=(i)%6;
        float yMultiplier= (i)/6;
        float xPos=xMultiplier*imageWidth;
        float yPos=1+UA_TOP_WHITE+UA_TOP_BAR_HEIGHT+yMultiplier*imageHeight;
        UIView *greyRect=[[UIView alloc]initWithFrame:CGRectMake(xPos, yPos, imageWidth, imageHeight)];
        [greyRect setBackgroundColor:UA_NAV_CTRL_COLOR];

        greyRect.layer.borderColor=[UA_NAV_BAR_COLOR CGColor];
        greyRect.layer.borderWidth=1.0f;
        greyRect.userInteractionEnabled=YES;
        [greyGridArray addObject:greyRect];
        [self.view addSubview:greyRect];
        NSLog(@"greyGrid: %i: %@", i, greyRect);

        //make them touchable
        UITapGestureRecognizer *letterTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(highlightLetter)];
        letterTapRecognizer.numberOfTapsRequired = 1;
        [greyRect addGestureRecognizer:letterTapRecognizer];
    }
12

12 Answers

119
votes

Define your target selector(highlightLetter:) with argument as

UITapGestureRecognizer *letterTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(highlightLetter:)];

Then you can get view by

- (void)highlightLetter:(UITapGestureRecognizer*)sender {
     UIView *view = sender.view; 
     NSLog(@"%d", view.tag);//By tag, you can find out where you had tapped. 
}
18
votes

Its been a year asking this question but still for someone.

While declaring the UITapGestureRecognizer on a particular view assign the tag as

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gestureHandlerMethod:)];
[yourGestureEnableView addGestureRecognizer:tapRecognizer];
yourGestureEnableView.tag=2;

and in your handler do like this

-(void)gestureHandlerMethod:(UITapGestureRecognizer*)sender {
    if(sender.view.tag == 2) {
        // do something here
    }
}
9
votes

Here is an update for Swift 3 and an addition to Mani's answer. I would suggest using sender.view in combination with tagging UIViews (or other elements, depending on what you are trying to track) for a somewhat more "advanced" approach.

  1. Adding the UITapGestureRecognizer to e.g. an UIButton (you can add this to UIViews etc. as well) Or a whole bunch of items in an array with a for-loop and a second array for the tap gestures.
    let yourTapEvent = UITapGestureRecognizer(target: self, action: #selector(yourController.yourFunction)) 
    yourObject.addGestureRecognizer(yourTapEvent) // adding the gesture to your object
  1. Defining the function in the same testController (that's the name of your View Controller). We are going to use tags here - tags are Int IDs, which you can add to your UIView with yourButton.tag = 1. If you have a dynamic list of elements like an array you can make a for-loop, which iterates through your array and adds a tag, which increases incrementally

    func yourFunction(_ sender: AnyObject) {
        let yourTag = sender.view!.tag // this is the tag of your gesture's object
        // do whatever you want from here :) e.g. if you have an array of buttons instead of just 1:
        for button in buttonsArray {
          if(button.tag == yourTag) {
            // do something with your button
          }
        }
    }
    

The reason for all of this is because you cannot pass further arguments for yourFunction when using it in conjunction with #selector.

If you have an even more complex UI structure and you want to get the parent's tag of the item attached to your tap gesture you can use let yourAdvancedTag = sender.view!.superview?.tag e.g. getting the UIView's tag of a pressed button inside that UIView; can be useful for thumbnail+button lists etc.

5
votes

in swift it quite simple

Write this code in ViewDidLoad() function

let tap = UITapGestureRecognizer(target: self, action: #selector(tapHandler(gesture:)))
    tap.numberOfTapsRequired = 2
    tapView.addGestureRecognizer(tap)

The Handler Part this could be in viewDidLoad or outside the viewDidLoad, batter is put in extension

@objc func tapHandler(gesture: UITapGestureRecognizer) {
    currentGestureStates.text = "Double Tap"
} 

here i'm just testing the code by printing the output if you want to make an action you can do whatever you want or more practise and read

4
votes

Use this code in Swift

func tappGeastureAction(sender: AnyObject) {
    if let tap = sender as? UITapGestureRecognizer {
        let point = tap.locationInView(locatedView)
        if filterView.pointInside(point, withEvent: nil) == true {
            // write your stuff here                
        }
    }
}
2
votes

you can use

 - (void)highlightLetter:(UITapGestureRecognizer*)sender {
     UIView *view = sender.view; 
     NSLog(@"%d", view.tag); 
}

view will be the Object in which the tap gesture was recognised

2
votes

You can also use "shouldReceiveTouch" method of UIGestureRecognizer

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:     (UITouch *)touch {
     UIView *view = touch.view; 
     NSLog(@"%d", view.tag); 
}    

Dont forget to set delegate of your gesture recognizer.

2
votes

Typical 2019 example

Say you have a FaceView which is some sort of image. You're going to have many of them on screen (or, in a collection view, table, stack view or other list).

In the class FaceView you will need a variable "index"

class FaceView: UIView {
   var index: Int

so that each FaceView can be self-aware of "which" face it is on screen.

So you must add var index: Int to the class in question.

So you are adding many FaceView to your screen ...

let f = FaceView()
f.index = 73
.. you add f to your stack view, screen, or whatever.

You now add a click to f

f.addGestureRecognizer(UITapGestureRecognizer(target: self,
                           action: #selector(tapOneOfTheFaces)))

Here's the secret:

@objc func tapOneOfTheFaces(_ sender: UITapGestureRecognizer) {
    if let tapped = sender.view as? CirclePerson {
        print("we got it: \(tapped.index)")

You now know "which" face was clicked in your table, screen, stack view or whatever.

It's that easy.

1
votes

You should amend creation of the gesture recogniser to accept parameter (add colon ':')

UITapGestureRecognizer *letterTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(highlightLetter:)];

And in your method highlightLetter: you can access the view attached to recogniser:

-(IBAction) highlightLetter:(UITapGestureRecognizer*)recognizer
{
    UIView *view = [recognizer view];
}
1
votes

Swift 5

In my case I needed access to the UILabel that was clicked, so you could do this inside the gesture recognizer.

let label:UILabel = gesture.view as! UILabel

The gesture.view property contains the view of what was clicked, you can simply downcast it to what you know it is.

@IBAction func tapLabel(gesture: UITapGestureRecognizer) {

        let label:UILabel = gesture.view as! UILabel

        guard let text = label.attributedText?.string else {
            return
        }

        print(text)
}

So you could do something like above for the tapLabel function and in viewDidLoad put...

<Label>.addGestureRecognizer(UITapGestureRecognizer(target:self, action: #selector(tapLabel(gesture:))))

Just replace <Label> with your actual label name

0
votes

If you are adding different UIGestureRecognizer on different UIViews and want to distinguish in the action method then you can check the property view in the sender parameter which will give you the sender view.

0
votes
func tabGesture_Call
{
     let tapRec = UITapGestureRecognizer(target: self, action: "handleTap:")
     tapRec.delegate = self
     self.view.addGestureRecognizer(tapRec)
     //where we want to gesture like: view, label etc
}

func handleTap(sender: UITapGestureRecognizer) 
{
     NSLog("Touch..");
     //handling code
}