【问题标题】:UITapGestureRecognizer -Ignore tap on top object and pass it on to the object underneath of itUITapGestureRecognizer - 忽略顶部对象的点击并将其传递给其下方的对象
【发布时间】:2020-01-21 11:39:40
【问题描述】:

我有一个红色的SCNNode,它以 1/2 的方式悬停在蓝色的 SCNNode 上。我需要他们两个的dragEvent,所以当他们被刷过时,他们会移动(效果很好)。问题是我只需要蓝色节点的 tapEvent。

如果点击了红色节点,我尝试按照answer herereturn nil,以便它可以继续到蓝色节点。它无法返回 nil,因为没有返回值:Unexpected non-void return value in void function

if hitResult.node.name == "Red" {

    return nil // Unexpected non-void return value in void function
}

if hitResult.node.name == "Blue" {
    // do something
}

如何在点击红色节点时忽略触摸事件,并将触摸事件继续到其下方的蓝色节点?

let tapGesture = UITapGestureRecognizer(target: self, action: #selector(nodeWasTapped(_:)))
sceneView.addGestureRecognizer(tapGesture)

func nodeWasTapped(_ recognizer: UITapGestureRecognizer) {

    guard let sceneView = recognizer.view as? ARSCNView else { return }

    let touchLocation: CGPoint = recognizer.location(in: sceneView)

    let hitResults = sceneView.hitTest(touchLocation, options: [:])

    if !hitResults.isEmpty {

        guard let hitResult = hitResults.first else { return }

        if hitResult.node.name == "Red" {

            // *** ignore this tap and continue to the blue node ***
        }

        if hitResult.node.name == "Blue" {
            // do something
        }
    }
}

【问题讨论】:

  • 您是否尝试过删除if hitResult.node.name == "Red" {} 并查看是否执行了另一个 if 语句?
  • 是的,没有红色语句,蓝色语句工作正常,但有红色语句,红色节点下方的蓝色节点的 1/2 无法接收点击
  • 也许您可以使用触摸位置来查看节点被点击的确切位置。就像,如果点击红色节点的下半部分,则忽略第一个 if 语句。
  • 这就是问题所在。如何忽略红色的下半部分并让它将触摸事件传递给蓝色节点?在我添加的链接中,返回 nil 是让触摸事件传递到它下面的任何东西的原因。例如,为红色返回 nil 会让蓝色节点接收到点击。问题是我不能返回 nil
  • 是的,你说得对,返回值在这里不起作用。你可以做的是get the coordinates of the red node,然后使用一些数学将这些坐标与touchLocation 的x 和y 值进行比较。如果点击红色节点的下半部分,则忽略红色 if 语句。否则,执行红色 if 语句。

标签: ios swift uitapgesturerecognizer


【解决方案1】:

使用下面的gestureRecognizer的委托方法来做到这一点

将委托添加到您的识别器

//when creating tapreconizer assign delegate too or may be are doing it already
yourTapRecognizer.delegate = self


func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if touch.view?.isDescendant(of: yourSubView) ?? false {
        return false
    }
    return true
}

【讨论】:

  • 嗨,我在哪里使用这个方法中的红色节点来代替 yourSubView?例如红色节点和蓝色节点都是 SCNNode 类型。使用此示例如何区分红色节点和蓝色节点?
  • SCNNode 也不能用来代替 yourSubView 因为它需要 UIView 类型。
  • 嗨,答案不起作用,您没有提供有关如何实际使用代码的任何上下文。如果其他人想知道如何在 ARSCNView 中使用 Abu 的代码,答案在这里:stackoverflow.com/a/51907242/4833705。使用 touchesBegan 里面的代码
【解决方案2】:

如果您不希望红色节点接收任何点击,只需删除两个if 语句,因为无论用户在红色和蓝色节点上按下哪个位置,您的目标都是执行相同的代码:

let tapGesture = UITapGestureRecognizer(target: self, action: #selector(nodeWasTapped(_:)))
sceneView.addGestureRecognizer(tapGesture)

func nodeWasTapped(_ recognizer: UITapGestureRecognizer) {

    guard let sceneView = recognizer.view as? ARSCNView else { return }

    let touchLocation: CGPoint = recognizer.location(in: sceneView)

    let hitResults = sceneView.hitTest(touchLocation, options: [:])

    if !hitResults.isEmpty {

        guard let hitResult = hitResults.first else { return }

        //Do something here, no need for if statements
    }
}

【讨论】:

  • 我试图让问题尽可能简单,但还有其他节点在被点击时都会做一些事情。 if 语句是必要的,例如,当点击蓝色时打印蓝色,但当点击黄色时打印黄色。如果没有 if 语句,当我点击蓝色节点时,黄色也会打印出来。
  • 啊,现在我看到了问题所在。然后你可以只使用这个if 语句而不是你当前的两个if 语句:if hitResult.node.name == "Red" || hitResult.node.name == "Blue" 然后做点什么。这行得通吗?
  • 不,我之前尝试过,结果相同。我将代码添加到@AbuUlHassan,这与添加返回语句没有什么不同,因为蓝色视图永远不会通过。我必须四处搜索并找到类似的东西。谢谢您的帮助。我真的很感激:)
  • @LanceSamaria 嗯,这真的很有趣。您是否尝试过在那里设置断点以查看 hitResult.node.name 实际上是什么?
  • 是的,无论按下哪个节点,都会打印出正确的名称,区分触摸不是问题。我想我找到了一种使用 switch 语句和 fallthrough 的方法,但我必须添加很多代码,我现在正在尝试。给我一些,我完成后给你发消息
【解决方案3】:

我使用了switch statementfallthrough,它们有效,但有一个警告。在我的问题中,我只有一个红色节点和一个蓝色节点。一旦点击红色节点,它就会进入蓝色语句,但如果我有其他节点(我这样做),这不起作用。

由于我没有将其他节点添加到问题中,这是一个简单的解决方法。

func nodeWasTapped(_ recognizer: UITapGestureRecognizer) {

    guard let sceneView = recognizer.view as? ARSCNView else { return }

    let touchLocation: CGPoint = recognizer.location(in: sceneView)

    let hitResults = sceneView.hitTest(touchLocation, options: [:])

    if !hitResults.isEmpty {

        guard let hitResult = hitResults.first else { return }

        switch hitResult.node.name {

            case "Red":
                fallthrough

            default:
                // do whatever for the blue node
            }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-25
    • 2011-04-20
    • 1970-01-01
    • 2014-06-09
    • 1970-01-01
    • 1970-01-01
    • 2011-08-24
    相关资源
    最近更新 更多