- [CustomWindow hitTest:withEvent:]实现转发事件

时间:2012-06-20 05:17:52

标签: iphone objective-c ios events uiwindow

我有一个自定义窗口(应该在所有内容之上,包括键盘)以显示重叠的内容,例如在按下设备中的音量增大/减小按钮时看到的覆盖图。

所以我做了一个自定义窗口OverlayWindow到目前为止一切正常,后面的窗口正常接收它们的事件。但是hitTest:withEvent:会多次调用,有时甚至会返回nil。我想知道这是正常/正确吗?如果没有,我该如何解决?

// A small (WIDTH_MAX:100) window in the center of the screen. If it matters
const CGSize screenSize = [[UIScreen mainScreen] bounds].size; 
const CGRect rect = CGRectMake(((int)(screenSize.width - WIDTH_MAX)*0.5),
       ((int)(screenSize.height - WIDTH_MAX)*0.5), WIDTH_MAX, WIDTH_MAX);
overlayWindow = [[CustomWindow alloc] initWithFrame:rect];
overlayWindow.windowLevel = UIWindowLevelStatusBar; //1000.0
overlayWindow.hidden = NO; // I don't need it to be the key (no makeKeyAndVisible)

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    // Find the front most window (with the highest window level) and
    // call this method on that window. It should will make the event be
    // forwarded to it

    // Situation1: This method is called twice (or even more, it depend
    // on the number of windows the app has) per event: Why? Is this the
    // *normal* behaviour?

    NSLog(@" ");
    NSLog(@"Point: %@ Event: %p\n", NSStringFromCGPoint(point), event);
    UIView *view = nil;
    if (CGRectContainsPoint(self.bounds, point)) {
        NSLog(@"inside window\n");
        NSArray *wins = [[UIApplication sharedApplication] windows];
        __block UIWindow *frontMostWin = nil;
        [wins enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            NSLog(@"win: %@\n", obj);
            if ([obj windowLevel] >= [frontMostWin windowLevel] && obj != self) {
                frontMostWin = obj;
            }
        }];
        NSLog(@"frontMostWindow:%@\n finding a new view ...\n", frontMostWin);
        CGPoint p = [frontMostWindow convertPoint:point fromWindow:self];
        view = [frontMostWindow hitTest:p withEvent:event];

       // Situation2: sometimes view is nil here, Is that correct?
    }
    NSLog(@"resultView: %@\n", view);
    return view;
}

编辑:

我也注意到了

  1. 如果hitTest:withEvent:始终返回nil,它也会有效。这只是在我致电overlayWindow.hidden = NO;

  2. 如果我在[overlayWindow makeKeyAndVisible]中致电nil,则hitTest:withEvent:并不总是有效。看起来关键窗口需要正确实施命中测试方法吗?

  3. 我在这里错过了关于事件转发的内容吗?

3 个答案:

答案 0 :(得分:2)

frontMostWindow是指frontMostWin吗?

看起来即使我们只使用一个UIWindow,hitTest:withEvent:也会在其上执行至少2次。所以,我想这是正常的。

您可以在

处收到空
view = [frontMostWindow hitTest:p withEvent:event];

由于以下原因:

  • frontMostWindow本身为null(例如,如果只有一个窗口)
  • p是ouside frontMostWindow界限(例如,当frontMostWindow是键盘而你的触摸在其他地方时)
  • frontMostWindow将属性userInteractionEnabled设置为NO;

答案 1 :(得分:0)

hitTest:withEvent:多次调用是正常的。这可能是因为您只在叠加的窗口上显示UILabel或UIImageView,因此会自动提供触摸。

但是我觉得你并不需要另外一个OverlayWindow,相反你可能会在keyWindow的顶部考虑一个UIView。这应该使您的应用程序更清洁...

答案 2 :(得分:0)

我确实遇到了同样的问题。

我试图根据你的帖子解决它,并找到了另一种解决方案。

此代码在uiwindow中实现,覆盖在顶部。

当区域没有视图时,此代码将通过窗口传递事件。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    NSLog(@" ");
    NSLog(@"Point: %@ Event: %p\n", NSStringFromCGPoint(point), event);
    UIView *view = nil;
    
    UIView *resultView = [super hitTest:point withEvent:event];
    
    if (resultView == self) {
        NSLog(@"touched in transparent window !!");
        return nil;
    }

    NSLog(@"touched in view!!");
    return resultView;
 }

毕竟,谢谢。你的帖子非常有帮助。