I'm trying to work out the best method for finding the exact subview (if any) at a given CGPoint
in a UIView
.
Part of my scene/ViewController is a custom UIView
subclass (designed in a XIB), which presents a UIStackView
of subviews (also custom, XIB-designed).
The VC has a UITapGestureRecognizer
on that custom view, and in my @IBAction
, I want to identify which specific one of its subviews was tapped, then handle it accordingly:
@IBAction func handleTap(recognizer:UITapGestureRecognizer) {
let tapLocation = recognizer.location(in: recognizer.view)
if let subviewTapped = customView.subviewAtLocation(tapLocation) {
handleTapForSubview(subviewTapped)
}
}
However, I don't know how to implement that subviewAtLocation(CGPoint)
method. I wasn't able to find anything in the standard UIView methods.
Any advice on how it should be done would be welcome.
Alternatively, I considered adding a tap recognizer to each of the subviews instead, then delegating to the parent, then to the VC, but that feels inefficient, and like it's putting too much control logic in the views, rather than the VC.
Thank you.
A solution would be using the contains(point:)
method of CGRect
. The idea is to iterate over the stack view's subviews and check which subviews contains the touched point. Here:
@IBAction func handleTap(recognizer:UITapGestureRecognizer) {
let tapLocation = recognizer.location(in: recognizer.view)
let filteredSubviews = stackView.subviews.filter { subView -> Bool in
return subView.frame.contains(tapLocation)
}
guard let subviewTapped = filteredSubviews.first else {
// No subview touched
return
}
// process subviewTapped however you want
}