好的,基本上我有一个带有一系列稍微重叠的子视图的视图。当一个子视图被点击时,它通过一个非常简单的两条线移动到顶部(除其他外):
-(void)mouseDown:(NSEvent *)theEvent {
if (_selected) { // Don't do anything this subview is already in the foreground
return;
}
NSView *superview = [self superview];
[self removeFromSuperview];
[superview addSubview:self positioned:NSWindowAbove relativeTo:nil];
}
这工作正常,似乎是做到这一点的“正常”方式。
问题是我现在在视图中引入了一些拖动逻辑,所以我需要响应-mouseDragged:
. 不幸的是,由于视图已从视图层次结构中删除并在此过程中重新添加,因此我不能让视图进入前台并在相同的鼠标操作中被拖动。它接收mouseDown:
,但从不接收mouseDragged:
或任何后续事件。如果我离开鼠标并再次单击视图,它只会拖动,因为第二次单击不会进行任何视图层次结构的调整。
我能做些什么来让视图像这样移到前台,并继续接收后续事件-mouseDragged:
和-mouseUp:
事件?
我开始考虑在超级视图中覆盖-hitTest:
并拦截 mouseDown 事件,以便在视图实际接收到事件之前将其带到前台。这里的问题是,从内部-hitTest:
,我如何区分我实际执行命中测试的事件类型?我不想将子视图移动到其他鼠标事件的前台,例如 mouseMoved 等。
更新 | 在我的超级视图中,我实际上已经做到了这一点,但感觉就像是一个非常糟糕的代码气味,-hitTest:
直接触发了一个事件。
-(NSView *)hitTest:(NSPoint)aPoint {
NSView *view = [super hitTest:aPoint];
if ([view isKindOfClass:[EDTabView class]] && ![(EDTabView *)view isActive]) {
// Effectively simulate two mouseDown events in sequence for this special case
[view mouseDown:nil]; // Works because I know too much about the implementation
}
return view;
}
这有两点感觉不对。最大的是我在执行之前-hitTest:
甚至返回之前执行的操作,然后在-hitTest:
完成后执行 AppKit 处理的操作。第二个是我没有要传递的事件,所以我传递的是 nil。它在这种情况下有效,因为我知道事件处理程序实际上并不处理任何事件数据,但这并不是很好。另一种方法是将整个逻辑移到超级视图中,但这里的关注点分离感觉更糟。
更新 | 这个-hitTest:
黑客被破坏了......当我没有点击鼠标时它会被触发,例如当我将某些东西拖到视图顶部时。仍在寻找解决此问题的好方法。
答案可以从字面上指示视图如何在拖动操作期间离开并重新进入其父视图,或者(也许更优雅)将视图移动到前景的另一种方法,而不是[view removeFromSuperview]; [superview addSubview:view ...];
.