How to get all UIViews at my touch position?
In image below I need to get all UIViews in touches with the yellow line.
Snippet from UI hierarchy:
I looking for a similar function to SpriteKit where we use to get all nodes at point with
self.nodes(at: touch.location(in: self))
4 Answers
Answers 1
You have to traverse all views in the hierachy like:
extension UIView { func allViews(for touch: UITouch) -> [UIView] { return self.allViews(at: touch.location(in: self)) } func allViews(at point: CGPoint) -> [UIView] { var stack = [UIView]() var result = [UIView]() stack.append(self) while let view = stack.popLast() { let localPoint = view.convert(point, from: self) if view.bounds.contains(localPoint) { result.append(view) } stack.append(contentsOf: view.subviews) } return result } }
You can either start with any super view which contains all appropriate views (e.g the view of a view controller) or the window. The point for the second method must be relative to the bounds of the view which is represented by self
.
Answers 2
In UIKit the responder chain works like this, I think there is no way getting all the list, because it a touch "goes" until a responder catches it and not further.
Answers 3
func subviewsThatContain(point: CGPoint, in view: UIView) -> [UIView] { var views = [UIView]() for subview in view.subviews { if subview.frame.contains(subview.convert(point, from: self.view)) { views.append(subview) } views += subviewsThatContain(point: point, in: subview) } return views }
and function call look like this
var allViews = [self.view] + subviewsThatContain(in: self.view, point: touch.location(in: self.view))
Answers 4
You can use hittest to check all view hierarchies
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { guard let point = targetPoint, var view = super.hitTest(point, with: event) else { return } var views: [UIView] = [view] while view != nil { view = view.hitTest(point, with: event) if view != nil { views.append(view!) } } }
0 comments:
Post a Comment