Cocoa中View的层级与鼠标事件的派发和处理

View的层级

在Interface Builder中,约在下面的View层级约高

如下图

TestView2就显示在TestView1之上

在使用代码动态添加View时,Cocoa并不能为我们保证View的层级,比如我往TestView1里面添加一个subview,TestView2可能就显示在TestView1之上了。

这时候我们需要通过代码来手动排版一下。

如下

1
2
[self.testview2 removeFromSuperview];
[self.rootView addSubview:self.testview2 positioned:NSWindowAbove relativeTo:nil];

鼠标事件的派发与处理

查找需要派发鼠标事件的View

首先通过NSView的- (nullable NSView *)hitTest:(NSPoint)point方法,找到接收鼠标事件的View。

hitTest的调用过程是按照View显示的层级,从最外层的View开始,然后依次往下调用。最后会找到最深的并且显示在最前面的那个View。

父View的hitTest调用子类的hitTest来层层寻找。默认的,最后的子类在响应的point找不到更小的子类了就会返回自己。

View处理鼠标事件

找到需要派发的NSView后,就会发送响应的方法,比如- (void)mouseDown:(NSEvent *)event- (void)mouseDragged:(NSEvent *)event

通过自定义的View继承自NSView,重载这些方法,我们可以处理鼠标的事件。

继续派发

这里需要注意的是,在时间处理方法中,比如- (void)mouseDown:(NSEvent *)中,如果调用了[super mouseDown:event];

事件会继续派发下去

hitTest会继续执行,往下寻找下一个需要派发事件的View

其他

  • 对于透明的窗口,上面放一个透明的View,鼠标的事件是不会派发到这个View上面的,这时候需要对window设置一下:[window setIgnoresMouseEvents:NO]参见
请用金钱尽情的践踏我