13

我试图拦截在我的整个应用程序中发生的任何活动(即触摸)。

换句话说,我试图通知在我的主 UIView 中发生的任何触摸事件,其中包含我的其余控件。为此,我认为 UIView 的方法 -hitTest:withEvent: 是一个很好的解决方案。

但是,当我在调用 [super hitTest:... withEvent:...] 之前 NSLog 进入这个被覆盖的方法时,我看到我所做的任何触摸都会调用 3 次,并且我看不到我收到的事件有任何区别每次调用它。

以下是我的应用程序主视图中该方法的实现方式:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    NSLog(@"hitTest:withEvent called :");
    NSLog(@"Event: %@", event);
    NSLog(@"Point: %@", NSStringFromCGPoint(point));
    NSLog(@"Event Type: %d", event.type);
    NSLog(@"Event SubType: %d", event.subtype);
    NSLog(@"---");

    return [super hitTest:point withEvent:event];
}

这是我在此视图中单次触摸的 NSLog:

2010-11-29 14:09:26.892 Application[68818:207] hitTest:withEvent called :
2010-11-29 14:09:26.892 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37935.2 touches: {(
)}
2010-11-29 14:09:26.892 Application[68818:207] Point: {173, 498}
2010-11-29 14:09:26.892 Application[68818:207] Event Type: 0
2010-11-29 14:09:26.892 Application[68818:207] Event SubType: 0
2010-11-29 14:09:26.893 Application[68818:207] ---
2010-11-29 14:09:26.893 Application[68818:207] hitTest:withEvent called :
2010-11-29 14:09:26.893 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37935.2 touches: {(
)}
2010-11-29 14:09:26.893 Application[68818:207] Point: {173, 498}
2010-11-29 14:09:26.893 Application[68818:207] Event Type: 0
2010-11-29 14:09:26.893 Application[68818:207] Event SubType: 0
2010-11-29 14:09:26.893 Application[68818:207] ---
2010-11-29 14:09:26.893 Application[68818:207] hitTest:withEvent called :
2010-11-29 14:09:26.894 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37944.9 touches: {(
)}
2010-11-29 14:09:26.894 Application[68818:207] Point: {173, 498}
2010-11-29 14:09:26.894 Application[68818:207] Event Type: 0
2010-11-29 14:09:26.894 Application[68818:207] Event SubType: 0
2010-11-29 14:09:26.894 Application[68818:207] ---

我怎么能在这三个通知之间做出任何区别才能触发我只想为单次触摸执行一次的操作?

提前致谢 !

4

4 回答 4

10

确实有 3 次调用 hitTest。目前尚不清楚为什么,但我们可以通过前两个调用与完成前一个手势有关的事件的时间戳来推测 - 这些时间戳总是非常接近前一次触摸发生的时间,并且与当前时间。

这就是我确定要处理哪个 hitTest 的方式:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
  NSTimeInterval system = [[NSProcessInfo processInfo] systemUptime];

  if (system - event.timestamp > 0.1) {
    // not the event we were interested in
  } else {
    // use this call
  }
}
于 2010-12-27T05:28:17.697 回答
8

如果这对您来说仍然是个问题。

我找到了几个关于这个主题的例子和讨论,但正确的解决方案非常简单。

一般来说,hittest 在 UIView 或 UIScrollView 中被调用了 3 次——这是遍历视图层次结构的结果。

一个非常简单且对我来说总是合适的解决方案是:

在你实现的视图中实现函数 hittest

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

对我来说——所有三个函数调用的位置总是相同的——所以只需将位置存储在本地类中。

在 .h 文件中:

@interface MyScrollView : UIScrollView {
    CGPoint touchLocation_;
}

@property (nonatomic, readonly) CGPoint touchLocation;

在 .m 文件中

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    return [super hitTest:point withEvent:event];
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
// The point check you need    
    if(point.y != self.touchLocation.y){
        touchLocation_ = point;
    // The function call you need - just called once.
    }
    return [super pointInside:point withEvent:event];
}

这个解决方案在几个项目中非常适合我。

于 2012-04-04T11:17:41.440 回答
2

您收到的事件响应数量取决于视图层次结构。

此方法通过向每个子视图发送 pointInside:withEvent: 消息来遍历视图层次结构,以确定哪个子视图应接收触摸事件。如果 pointInside:withEvent: 返回 YES,则遍历子视图的层次结构;否则,其视图层次结构的分支将被忽略。您很少需要自己调用此方法,但您可能会覆盖它以隐藏子视图中的触摸事件。

此方法忽略隐藏、禁用用户交互或 alpha 级别小于 0.01 的视图对象。此方法在确定命中时不考虑视图的内容。因此,即使指定点位于视图内容的透明部分中,仍可以返回视图。

位于接收器边界之外的点永远不会被报告为命中,即使它们实际上位于接收器的子视图之一内。如果当前视图的 clipsToBounds 属性设置为 NO 并且受影响的子视图超出视图的边界,则会发生这种情况。

来自UIView 类参考

简而言之,如果您触摸的视图具有三个子视图,并且这些视图是可见的并且在其父视图和触摸区域的范围内,您将收到三个命中测试响应。

于 2010-11-29T13:24:44.797 回答
0

这个问题已经问了很多年了,但我想回答一下:

系统多次调用hitTest和pointInside来固定位置,每次调用栈都不一样,请参考苹果官方回复

于 2019-04-05T11:43:47.600 回答