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

Tho*_*ert 13 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];
}
Run Code Online (Sandbox Code Playgroud)

这是我在这个视图中单次触摸的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] ---
Run Code Online (Sandbox Code Playgroud)

我怎么能在这三个通知之间做出任何区别,以便触发我想只进行一次触摸的动作?

提前致谢 !

sds*_*kes 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
  }
}
Run Code Online (Sandbox Code Playgroud)


小智 8

如果这仍然是你的问题.

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

通常,在UIView或UIScrollView中调用hittest三次 - 这是遍历视图层次结构的结果.

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

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

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
Run Code Online (Sandbox Code Playgroud)

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

在.h文件中:

@interface MyScrollView : UIScrollView {
    CGPoint touchLocation_;
}

@property (nonatomic, readonly) CGPoint touchLocation;
Run Code Online (Sandbox Code Playgroud)

在.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];
}
Run Code Online (Sandbox Code Playgroud)

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


Eva*_*ski 2

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

\n\n
\n

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

\n\n

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

\n\n

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

\n
\n\n

来自UIView 类参考

\n\n

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

\n