- [CustomWindow hitTest: withEvent:] implementation for forwarding events

I have a custom window (which should be on top of everything, including the keyboard) to show the superimposed thing, something like the overlay that you see when you press the volume up / down buttons on the device.

So, I made my own OverlayWindow window, while everything is working fine, and windows in the back usually receive their events. However, hitTest:withEvent: is called several times, and sometimes even returns nil. I wonder if this is normal? If not, how can I fix this?

 // 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; } 

EDIT:

I also noticed that

  • If hitTest:withEvent: always returns nil , it works too. This only happens when I call overlayWindow.hidden = NO;

  • if I call [overlayWindow makeKeyAndVisible] returning nil in hitTest:withEvent: does not always work. It looks like the key window requires the correct implementation of the hit test method?

Am I missing something about event forwarding here?

+4
source share
3 answers

Does FrontMostWindow have frontMostWin?

It seems that even if we use only one UIWindow, hitTest:withEvent: will be executed on it at least 2 times. So, I think this is normal.

You can get null in

 view = [frontMostWindow hitTest:p withEvent:event]; 

the following reasons:

  • frontMostWindow is null (for example, if you have only one window)
  • p is ouside frontMostWindow bounds (for example, when frontMostWindow is the keyboard and your touch is in a different place).
  • frontMostWindow has the userInteractionEnabled property set to NO;
+2
source

hitTest: withEvent: the call several times is normal. This is probably due to the fact that you only display a UILabel or UIImageView in an overlay window, and thus touches are automatically recorded.

However, I think you do not need another OverlayWindow, instead you can consider the UIView at the top of keyWindow. This should make your application cleaner ...

0
source

I ran into the same problem.

I tried to solve this based on your post, and another solution was found.

This code is implemented in an overlay uiwindow.

This code will send events through the bottom window when the area is not visible.

 - (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; } 

In the end, thanks. Your post is very helpful.

0
source

All Articles