如何知道屏幕上的任何对象何时被点击?

时间:2021-09-19 08:55:27

Now first of all, I am not asking how to add a gesture recognizer or how to create a button. What I want is to know that "somebody touched the screen in any way", without interfering with the related screen element.

首先,我不是问如何添加手势识别器或如何创建按钮。我想要的是知道“有人以任何方式触摸屏幕”,而不会干扰相关的屏幕元素。

The thing is that I have elements that the user can tap on (amazing, isn't it?). Then I have a view that is overlaid on top of everything (window addSubview). This view shows up with some delay, and I want the app to behave as if this view wasn't there until its "show" animation starts. Then, if the user taps any of the mentioned elements, which are not and cannot all be superviews to the overlaid view, the element should highlight and trigger as usual, while the view to be overlaid should cancel its show animation (alpha 0->1) and remove itself from the hierarchy.

问题是我有用户可以点击的元素(太棒了,不是吗?)。然后我有一个覆盖在所有内容之上的视图(window addSubview)。这个视图显示有一些延迟,我希望应用程序的行为好像这个视图不存在,直到它的“显示”动画开始。然后,如果用户点击任何提到的元素,这些元素不是也不能全部是覆盖视图的超视图,则元素应该像往常一样突出显示并触发,而要覆盖的视图应该取消其显示动画(alpha 0-> 1)并从层次结构中删除自己。

tl;dr: How can I listen for any event for any object on the screen, without having to write explicit code to "watch" each of those objects — I just want to know that a gesture occured, not where, not how, not whatever? And I don't want to mess with the view that is the receiver of the event. Is this even possible?

tl; dr:我如何监听屏幕上任何对象的任何事件,而不必编写显式代码来“观察”每个对象 - 我只是想知道手势发生了,而不是在哪里,不是如何,不是随你?而且我不想搞砸作为事件接收者的观点。这甚至可能吗?

2 个解决方案

#1


You need to just subclass your main window, and you will find all touch events there. There is a handy catch-all method in UIWindow called sendEvent: which sees every event near the start of the event-handling pipeline. If you want to do any non-standard additional event handling, this is a good place to put it. Something like this:

您需要将主窗口子类化,然后您将在那里找到所有触摸事件。 UIWindow中有一个方便的catch-all方法,叫做sendEvent:它可以看到事件处理管道开始附近的每个事件。如果你想做任何非标准的额外事件处理,这是一个放置它的好地方。像这样的东西:

- (void)sendEvent:(UIEvent *)event {
  if ([self eventIsNoteworthy:event]) [self extraEventHandling:event];
  [super sendEvent:event];  // Apple says you must always call this!
}

Docs: UIWindow class reference | iOS event delivery docs

文档:UIWindow类引用| iOS事件传递文档

This blog post also mentions how to override hitTest:withEvent: to catch some events before they're bound to the target leaf subview in the view hierarchy. You can also override that method on your UIWindow object if you want.

这篇博客文章还提到了如何覆盖hitTest:withEvent:在绑定到视图层次结构中的目标叶子视图之前捕获一些事件。如果需要,您还可以在UIWindow对象上覆盖该方法。

Note : You will not get keyboard touch events through this solution.

注意:您不会通过此解决方案获得键盘触摸事件。

#2


In your overlay view, override hitTest: as follows:

在叠加视图中,覆盖hitTest:如下所示:

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
    let result = super.hitTest(point, withEvent:event)
    if result === self {
        println("tapped the view")
        return nil
    }
    return result
}

The outcome is that if the overlay view is tapped, it responds (as proven by the "tapped the view" output to the console) but it allows the tap to fall through to whatever is behind it (because it returns nil). This is, in effect, an untouchable view that nevertheless knows when it is touched.

结果是,如果点击叠加视图,它会响应(通过“点击视图”输出到控制台的证明),但它允许点击落入其后面的任何内容(因为它返回nil)。实际上,这是一种不可触摸的观点,但却知道它何时被触及。

#1


You need to just subclass your main window, and you will find all touch events there. There is a handy catch-all method in UIWindow called sendEvent: which sees every event near the start of the event-handling pipeline. If you want to do any non-standard additional event handling, this is a good place to put it. Something like this:

您需要将主窗口子类化,然后您将在那里找到所有触摸事件。 UIWindow中有一个方便的catch-all方法,叫做sendEvent:它可以看到事件处理管道开始附近的每个事件。如果你想做任何非标准的额外事件处理,这是一个放置它的好地方。像这样的东西:

- (void)sendEvent:(UIEvent *)event {
  if ([self eventIsNoteworthy:event]) [self extraEventHandling:event];
  [super sendEvent:event];  // Apple says you must always call this!
}

Docs: UIWindow class reference | iOS event delivery docs

文档:UIWindow类引用| iOS事件传递文档

This blog post also mentions how to override hitTest:withEvent: to catch some events before they're bound to the target leaf subview in the view hierarchy. You can also override that method on your UIWindow object if you want.

这篇博客文章还提到了如何覆盖hitTest:withEvent:在绑定到视图层次结构中的目标叶子视图之前捕获一些事件。如果需要,您还可以在UIWindow对象上覆盖该方法。

Note : You will not get keyboard touch events through this solution.

注意:您不会通过此解决方案获得键盘触摸事件。

#2


In your overlay view, override hitTest: as follows:

在叠加视图中,覆盖hitTest:如下所示:

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
    let result = super.hitTest(point, withEvent:event)
    if result === self {
        println("tapped the view")
        return nil
    }
    return result
}

The outcome is that if the overlay view is tapped, it responds (as proven by the "tapped the view" output to the console) but it allows the tap to fall through to whatever is behind it (because it returns nil). This is, in effect, an untouchable view that nevertheless knows when it is touched.

结果是,如果点击叠加视图,它会响应(通过“点击视图”输出到控制台的证明),但它允许点击落入其后面的任何内容(因为它返回nil)。实际上,这是一种不可触摸的观点,但却知道它何时被触及。