开发者

Click through NSView

I have an NSView containing multiple subviews. One of those subviews is transparent and layered on top.

I need to be able to click through this view down to t开发者_如何学Gohe subviews below (so that the view below gets first responder status), but all the mouse events get stuck on the top view (alpha is 1, because I draw stuff in it - so it should only click through transparent areas).

I actually expected this to work, since normally it does. What's wrong?


Here's another approach. It doesn't require creating a new window object and is simpler (and probably a bit more efficient) than the findNextSiblingBelowEventLocation: method above.

- (NSView *)hitTest:(NSPoint)aPoint
{
    // pass-through events that don't hit one of the visible subviews
    for (NSView *subView in [self subviews]) {
        if (![subView isHidden] && [subView hitTest:aPoint])
            return subView;
    }

    return nil;
}


I circumvented the issue with this code snippet.

- (NSView *)findNextSiblingBelowEventLocation:(NSEvent *)theEvent {
  // Translate the event location to view coordinates
  NSPoint location = [theEvent locationInWindow];
  NSPoint convertedLocation = [self convertPointFromBase:location];

  // Find next view below self
  NSArray *siblings = [[self superview] subviews];
  NSView *viewBelow = nil;
  for (NSView *view in siblings) {
    if (view != self) {
      NSView *hitView = [view hitTest:convertedLocation];
      if (hitView != nil) {
        viewBelow = hitView;
      }
    }
  }
  return viewBelow;
}

- (void)mouseDown:(NSEvent *)theEvent {
  NSView *viewBelow = [self findNextSiblingBelowEventLocation:theEvent];
  if (viewBelow) {
    [[self window] makeFirstResponder:viewBelow];
  }
  [super mouseDown:theEvent];
}


Here's a Swift 5 version of figelwump's answer:

public override func hitTest(_ point: NSPoint) -> NSView? {
    // pass-through events that don't hit one of the visible subviews
    return subviews.first { subview in
        !subview.isHidden && nil != subview.hitTest(point)
    }
}


Here's a Swift 5 version of Erik Aigner's answer:

public override func mouseDown(with event: NSEvent) {
    // Translate the event location to view coordinates
    let convertedLocation = self.convertFromBacking(event.locationInWindow)

    if let viewBelow = self
        .superview?
        .subviews // Find next view below self
        .lazy
        .compactMap({ $0.hitTest(convertedLocation) })
        .first
    {
        self.window?.makeFirstResponder(viewBelow)
    }

    super.mouseDown(with: event)
}


Put your transparent view in a child window of its own.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜