如何在我的触摸位置获取层次结构中的所有视图 - Swift
Posted
技术标签:
【中文标题】如何在我的触摸位置获取层次结构中的所有视图 - Swift【英文标题】:How to get all views in hierarchy in my touch position - Swift 【发布时间】:2018-03-05 13:56:27 【问题描述】:如何在我的触摸位置获取所有 UIView?
在下图中,我需要让所有 UIView 都与黄线接触。
来自 UI 层次结构的片段:
我正在寻找与 SpriteKit 类似的功能,我们用它来获取所有节点
self.nodes(at: touch.location(in: self))
【问题讨论】:
如果你正在寻找 UIViews 那么你应该用 UIKit 来标记它,而不是 SpriteKit 【参考方案1】:您必须遍历层次结构中的所有视图,例如:
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
您可以从包含所有适当视图(例如视图控制器的视图)或窗口的任何超级视图开始。第二种方法的点必须相对于由self
表示的视图边界。
【讨论】:
为什么 break 语句意味着永远不会发生? @Saranjith:只有在堆栈不为空时才会进入while循环。因此,stack.popLast()
应该总是返回一个视图。
@clemens 然后强制解开stack.popLast()
或使用while let view = stack.popLast()
开始。
@ChristianSchnorr:谢谢,很好的提示。我已经修改了我的帖子。【参考方案2】:
这可以通过两步来实现:
获取从某个视图开始的所有视图
func descendants(of view: UIView) -> [UIView]
return view.subviews + view.subviews.flatMap(descendants(of:))
过滤包含接触点的视图:
let touchLocation = touchGesture.location(in: nil)
let matchingViews = descendants(of: UIApplication.shared.keyWindow!)
.filter $0.convert($0.bounds, to: nil).contains(touchLocation)
【讨论】:
【参考方案3】:在 UIKit 中,响应者链的工作方式类似于 this,我认为没有办法获取所有列表,因为它会“继续”直到响应者捕获它而不是进一步。
【讨论】:
【参考方案4】: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
函数调用看起来像这样
var allViews = [self.view] + subviewsThatContain(in: self.view, point: touch.location(in: self.view))
【讨论】:
【参考方案5】:您可以使用 hittest 检查所有视图层次结构
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!)
【讨论】:
这并不适用于所有情况,因为hitTest()
需要一个相对于视图边界的点。它不会找到被另一个视图覆盖的视图。它也可能包含一个无限循环,因为hitTest()
可能会返回视图本身。以上是关于如何在我的触摸位置获取层次结构中的所有视图 - Swift的主要内容,如果未能解决你的问题,请参考以下文章
iOS CALayer.zPosition 不会超越视图层次结构吗?