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

问题描述 投票:13回答:4

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

换句话说,我正在尝试通知我的主要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] ---

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

提前致谢 !

iphone events uiview hittest
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
  }
}

8
投票

如果这仍然是你的问题。

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

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

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

在您实现的视图中实现函数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];
}

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


2
投票

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

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

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

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

来自UIView Class Reference

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


0
投票

多年来一直在问这个问题,但我想回答一下:

系统多次调用hitTest和pointInside来修复位置,每次调用堆栈不同时,请参考apple中的the official reply

© www.soinside.com 2019 - 2024. All rights reserved.