Щелкните NSView

У меня есть NSView, содержащий несколько подзонов. Одно из этих представлений является прозрачным и многослойным сверху.

Мне нужно иметь возможность щелкнуть этот вид вниз до подзаголовков ниже (так, чтобы вид ниже получил статус первого ответчика), но все события мыши застревают в верхнем виде (альфа 1, потому что я нарисуйте материал в нем - так что он должен только щелкать прозрачными областями).

Я действительно ожидал, что это сработает, так как обычно это происходит. Что не так?

Ответ 1

Вот еще один подход. Это не требует создания нового оконного объекта и проще (и, вероятно, немного более эффективно), чем метод findNextSiblingBelowEventLocation: выше.

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

Ответ 2

Я обошел проблему с этим фрагментом кода.

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

Ответ 3

Поместите свой прозрачный вид в собственное дочернее окно.

Ответ 4

Вот версия figelwump от Swift 5:

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)
    }
}

Ответ 5

Вот версия Erik Aigner от Swift 5:

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)
}