UIView的-hitTest:withEvent:调用了三次?

时间:2010-11-29 13:18:09

标签: iphone events uiview hittest

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

换句话说,我正在尝试通知我的主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 个答案:

答案 0 :(得分: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
  }
}

答案 1 :(得分:8)

如果这仍然是您的问题。

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

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

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

在您实施的视图中实现功能hittest

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

对我来说 - 所有三个函数调用都始终保持相同的位置 - 所以只需将位置存储在本地类中。

<。>文件中的

@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];
}

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

答案 2 :(得分:2)

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

  

此方法遍历视图   层次结构发送   pointInside:withEvent:发送给每个人的消息   子视图确定哪个子视图   应该收到触摸事件。如果   pointInside:withEvent:返回YES,   然后子视图的层次结构是   走过;否则,它的分支   视图层次结构被忽略。您   很少需要调用此方法   你自己,但你可以覆盖它   隐藏子视图中的触摸事件。

     

此方法忽略视图对象   隐藏,已禁用用户   交互,或具有alpha级别   小于0.01。这种方法没有   将视图的内容考虑在内   在确定命中时。因此,一个观点   即使是,仍然可以返回   指定的点是透明的   该视图内容的一部分。

     

位于接收者之外的点   边界从未被报告为命中,   即使他们实际上是在一个人之内   接收者的子视图。这个可以   如果当前视图出现   clipsToBounds属性设置为NO   受影响的子视图延伸   超出视野范围。

来自UIView Class Reference

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

答案 3 :(得分:0)

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

系统多次调用hitTest和pointInside来固定位置,并且每次调用堆栈都不相同时,请从Apple咨询the official reply