hitTest on iOS to identify the view being hit
HitTest on iOS
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
}
Here is a simple implementation of the method, to identify the view being hit.
Blue(parent)
- Red(child)
- Green(child)
- Yellow (child)
- Orange (child)
- Black (child)
- White (child)
So lets' start with override of hitTest method.
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
//1
if let viewAvailable = findPointsInsideView(parent: self, point: point, event: event) {
return viewAvailable
}
//2
if self.point(inside: point, with: event) {
return self
}
return nil
}
1. We identify if the point is inside any of the sub view's of the main parent view.
2. If we don't receive any sub-view which includes the given point we check if the it's the parent view who actually received the hit.
Below is a helper method which traverses through the subview's to identify the if the point belongs to any of the subview.
private func findPointsInsideView(parent: UIView, point: CGPoint, event: UIEvent?) -> UIView? {
let allChilds = parent.subviews
//1
guard allChilds.count > 0 else {
return nil
}
//2
for babyView in allChilds.reversed() {
//3
let modifiedPoint = parent.convert(point, to: babyView)
//4
if babyView.point(inside: modifiedPoint, with: event){
//5
if let foundView = findPointsInsideView(parent: babyView, point: modifiedPoint, event: event) {
return foundView
} else {
return babyView
}
}
}
return nil
}
1. Check if the parent has further child view's or not. This is usually useful if the view receiving the touch is at the end in the hierarchy.
If the count of subview's is 0 , there is no point in traversing further.
In the above case if we tap on Black View , it does not traverse further.
2. We traverse from the top most view in the hierarchy.
So the reverse order of traversing would be "White View" -> "Green View" and "Red View"
If we don't use reversed() function, tapping on Green area which overlaps with Red View, findPointsInsideView will return the RedView itself as the func point(inside point: CGPoint, with event: UIEvent?) -> Bool , will turn true
This can be seen in below picture , where if we tap on brown scribbled area we should return Green View not the Red View.
- x : 120.5
- y : 318.0
However for the blackView to check if the modifiedPoint is inside the babyView or not (i.e BlackView) we would need this translation.
modifiedPoint value will be
▿ (31.5, 9.0)
- x : 31.5
- y : 9.0
Comments
Post a Comment