你知道当你从停靠栏中拖出一个项目并且那个云拖动光标出现时会产生什么效果,当你放开它时会消失效果?类似地,在Xcode中,当您在行号装订线外拖动断点时,也会发生相同的情况。
我想在我的应用程序中实现相同的效果,但找不到正确的方法。
我有一个NSImageView后代来实现NSDraggingSource和NSDraggingDestination协议。我有这个视图的几个实例,允许在其他视图之间拖动它们的内容(在这种情况下进行复制操作,但这只与显示我已经拖拽并完全适用于标准任务)。
现在,当我将图像从视图拖到任何地方(另一个视图实例除外)时,我希望删除操作在drop上进行。但是,拖动操作完全由目标视图控制。我可以设法让它们以我想要的方式响应(即使这会有很多工作),但是如果我拖到我的应用程序之外它就会完全失败。
如果我可以获得删除拖动操作,我可以通过以下方式轻松处理:
- (void)draggedImage: (NSImage *)image
endedAt: (NSPoint)screenPoint
operation: (NSDragOperation)operation
{
if (operation == NSDragOperationDelete) {
NSRect rect = [self.window convertRectToScreen: [self convertRect: self.frame fromView: nil]];
NSShowAnimationEffect(NSAnimationEffectPoof, rect.origin, self.bounds.size, nil, nil, NULL);
}
}
我已经尝试过像这样设置删除游标:
- (void)draggingSession: (NSDraggingSession *)session
movedToPoint: (NSPoint)screenPoint
{
if (!NSPointInRect(screenPoint, self.window.frame)) {
[[NSCursor disappearingItemCursor] set];
}
}
(为简单起见,这是目前的整个风)。只要我没有点击桌面或取景器窗口,这就可以工作。在开始闪烁时,可能是因为Finder同时设置了自己的拖动光标。当我撞到码头时它完全没有效果。当我定义自己的粘贴板数据类型时也会发生这种情况。
此外,我的应用程序中任何其他启用drop的视图仍然会接受我不希望发生的拖动数据(例如NSTextView)(我正在使用自定义方案将NSURL写入拖动粘贴板)。
更新
我已经走了几步。正如彼得已经指出的那样处理draggingSession:sourceOperationmaskForDraggingContext:
是必不可少的,这在我的代码中是如此:
- (NSDragOperation) draggingSession: (NSDraggingSession *)session
sourceOperationMaskForDraggingContext: (NSDraggingContext)context;
{
switch(context) {
case NSDraggingContextOutsideApplication:
return NSDragOperationDelete;
break;
case NSDraggingContextWithinApplication:
default:
return NSDragOperationDelete | NSDragOperationMove;
break;
}
}
这解决了2个问题:1)在应用程序之外根本不接受拖动操作,2)它使所有标准视图也不接受此操作(因为NSOutlineView,NSTextView等不处理给定的拖动操作) 。另外,我创建了一个自己的粘贴板数据类型,但这似乎没有必要。还是有一个自己的更清楚。
不幸的是,掉到我的NSImageView后代之外(在应用程序内外)并没有给我draggedImage:endedAt:operation:
(我上面指定的)NSDragOperationDelete但NSDragOperationNone。此外,在应用程序外移动鼠标时的拖动光标是不允许的,而不是消失项。所以,如果有人能够解决这两件事,我会接受它作为我问题的答案。
答案 0 :(得分:2)
可能有一种不太常见的方式,但我可以想到一种可能性:一旦拖动开始,创建一个透明的无边框窗口,桌面大小为虚拟拖动目的地。您可能需要使用-setIgnoresMouseEvents:
拨打NO
以允许它接收丢弃,即使它是透明的。您还必须将其窗口级别设置在菜单栏(NSMainMenuWindowLevel + 1)上方,以确保窗口仍然截获到菜单栏或Dock的拖动。
作为拖动目的地,此窗口必须检查您的某个图像视图是否在光标下。您可以使用+[NSWindow windowNumberAtPoint:belowWindowWithWindowNumber:]
查找光标下透明覆盖窗口下方的窗口。然后使用-[NSApplication windowWithWindowNumber:]
确定它是否是您应用的一个窗口,如果是,请在其内容视图上调用-[NSView hitTest:]
(根据需要转换光标坐标)以查找视图。然后,您可以根据需要将NSDraggingDestination
方法转发到该视图。
答案 1 :(得分:2)
我的猜测是NSDragOperationDelete仅涉及针对 dock的Trash 的拖放,而不是其他任何内容。
NSDragOperationGeneric 应该更合适。 一定不要混合方法,如果你要使用10.7路线,请选择:
-(void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation
答案 2 :(得分:0)
OS X 10.7或更高版本:
- (void) draggingEnded: (id<NSDraggingInfo>) aInfo {
/*! Delete the current leaf if it is no longer represented in the subviews. */
RETURN_IF ( , NSNotFound != [self.visibleLeafs indexOfObject: iSelectedControl.representedObject] );
iIgnoreLeafsObservation = YES;
[self.leafs removeObject: iSelectedControl.representedObject];
iIgnoreLeafsObservation = NO;
}
这假设您已经在视觉上删除了对象。您还可以在draggingEntered:和draggingExited:期间设置一个标志,以指示拖动会话是在最后一个内部还是外部。
在此程序中,leafs是实际观察到的集合,而visibleLeafs是每个可见控件的representObject的模拟集合。其他NSDraggingDestination重载表示在实际发生之前会在视觉上发生的事情。
答案 3 :(得分:0)
我刚刚完成了与您所描述的非常相似的操作。您的代码与我的代码非常相似,但有一些例外:
在使用draggedImage:endedAt:operation:
的地方,我在使用draggingSession:session:endedAt:operation:
。另外,在这种方法中,由于我所有的操作都设置为generic
,所以我不检查该操作。这也是我执行实际删除操作的地方,因此,仅在删除成功后才显示poof动画。
在您的draggingSession:session:movedToPoint:
中,当该点位于窗口之外时,您可能还希望将session
的{{1}}设置为animatesToStartingPositionsOnCancelOrFail
(这也是在您设置false
),否则设置为disappearingItemCursor
。这增加了最后的触动,一旦删除操作完成,被拖动的图像就不会反弹回其原始源位置。
至于为什么您看不到正确的光标,我的猜测是您使用的是其他东西(Finder等)愿意接受的Pasteboard类型。我知道您说过您创建了自己的Pastboard数据类型,但是我会再次检查它们是否正在使用。当我创建自己的类型时,我获得了对游标的控制。至少,我找不到与我的自定义类型竞争的内容。
答案 4 :(得分:-3)
您可以使用以下命令使poof出现在鼠标位置:
NSShowAnimationEffect(NSAnimationEffectPoof, [NSEvent mouseLocation], NSZeroSize, NULL, NULL, NULL);
有关详细信息,请参阅Application Kit Functions Reference。