9

I am trying to check if a tap is happening in a specific region on the screen. I've set up a TapGestureRecognizer this is the code I have right now:

func handleTap(tap: UITapGestureRecognizer) {
    var point = tap.locationInView(self.view)
    println("tapped")

    if (tap.state == UIGestureRecognizerState.Ended)
    {
        if (CGRectContainsPoint(self.Region.frame, point)) {
            println("touch")
            var y = kbHeight - textYoutube.center.y
            youTextConst.constant += y
        }
    }
}

The app recognized the tap but not the tap in the specific region, What's wrong with the code?

UPDATE

I don't know if it matters but the Region is a TextView

Omer
  • 221
  • 3
  • 13
  • 3
    Think about the different coordinate systems you're using here... – matt Mar 06 '15 at 16:20
  • Before you can call CGRectContainsPoint you need a rect and a point _in the same coordinate system_. What I would do is convert `point` to the coordinate system of `self.Region` itself, and now compare `point` to `self.Region.bounds`. See my book: http://www.apeth.com/iOSBook/ch14.html#_frame and http://www.apeth.com/iOSBook/ch14.html#_bounds_and_center – matt Mar 06 '15 at 16:54

3 Answers3

13

(NOTE: I am assuming that self.Region is a UIView. You do not explain what it is in your question, so I have to guess what it might be. By the way, please do not use a capital letter for the name of a property. I am doing this only to give you an easy match to your own code.)

Think about coordinate systems. You are saying

var point = tap.locationInView(self.view)

That means that point is in self.view's coordinate system. But that's the wrong coordinate system if you're going to call CGRectContainsPoint. Before you can work out the relationship between point and self.Region, you need to get point into the same coordinate system as self.Region:

point = self.Region.convertPoint(point, fromView:self.view)

Now you can use self.Region.bounds, which is in the same coordinate system as the new value of point:

if CGRectContainsPoint(self.Region.bounds, point)
matt
  • 515,959
  • 87
  • 875
  • 1,141
3

My first answer, even with the sketch, was messy. I've deleted it.

So here are multiple ways to achieve what you're looking for. We'll assume that your region is an UIView.

Solution 1

You are retrieving the point from the main view, so you need to check if the frame of your regionView contains your point.

import UIKit

class ViewController: UIViewController {

    @IBOutlet var regionView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let tap = UITapGestureRecognizer()
        tap.addTarget(self, action: "handleTap:")

        self.view.addGestureRecognizer(tap)
    }

    func handleTap(tap: UITapGestureRecognizer) {
        if (tap.state == UIGestureRecognizerState.Ended) {
            println("[handleTap] Tap ended")

            var point = tap.locationInView(self.view)

            println("[handleTap] Tap point : x\(point.x) ; y\(point.y) (in self.view)")

            if (CGRectContainsPoint(self.regionView.frame, point)) {
                println("[handleTap] Tap is inside regionView")
            }

            println()
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

Solution 2

You are retrieving the point and convert it to the inside regionView coordinates system. So you need to check if the point is within bounds of your regionView.

import UIKit

class ViewController: UIViewController {

    @IBOutlet var regionView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let tap = UITapGestureRecognizer()
        tap.addTarget(self, action: "handleTap:")

        self.view.addGestureRecognizer(tap)
    }

    func handleTap(tap: UITapGestureRecognizer) {
        if (tap.state == UIGestureRecognizerState.Ended) {
            println("[handleTap] Tap ended")

            var point = tap.locationInView(self.view)

            println("[handleTap] Tap point : x\(point.x) ; y\(point.y) (in self.view)")

            point = self.regionView.convertPoint(point, fromView: self.view)

            println("[handleTap] Tap point converted : x\(point.x) ; y\(point.y) (in self.regionView)")

            if (CGRectContainsPoint(self.regionView.bounds, point)) {
                println("[handleTap] Tap is inside regionView")
            }

            println()
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

Solution 3

You get the point from your regionView directly. So you don't need to convert it, however you still need to check if it's within its bounds like solution 2.

import UIKit

class ViewController: UIViewController {

    @IBOutlet var regionView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let tap = UITapGestureRecognizer()
        tap.addTarget(self, action: "handleTap:")

        self.view.addGestureRecognizer(tap)
    }

    func handleTap(tap: UITapGestureRecognizer) {
        if (tap.state == UIGestureRecognizerState.Ended) {
            println("[handleTap] Tap ended")

            var point = tap.locationInView(self.regionView)

            println("[handleTap] Tap point : x\(point.x) ; y\(point.y) (in self.view)")

            if (CGRectContainsPoint(self.regionView.bounds, point)) {
                println("[handleTap] Tap is inside regionView")
            }

            println()
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

Alternatively, you can only set your gesture recognizer on the regionView : self.regionView.addGestureRecognizer(tap).

Let me know if it helped !

lchamp
  • 6,592
  • 2
  • 19
  • 27
  • The region is a textField, I think that's why your code doesn't work for me, when i checked it on an image it works fine. – Omer Mar 07 '15 at 17:42
  • perfect solution! I was looking for a way to dismiss controller by tapping outside an imageview and with any reason touchesBegan wasn't working on the view but this solution worked! – Samira Aug 17 '18 at 19:03
1

Swift 5:

func handleTap(recognizer: UITapGestureRecognizer) {
    if (recognizer.state == .ended) {
        let point = recognizer.location(in: self.view)
        
        if (self.headerView.frame.contains(point)) {
            // Do something
        }
        
    }
}
David
  • 857
  • 1
  • 11
  • 25