Wednesday, March 14, 2018

How to get all views in hierarchy in my touch position - Swift

Leave a Comment

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:

enter image description here

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!)             }         }     } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment