14

您知道当您从 Dock 中拖出一个项目并出现云拖动光标时的效果,当您放手时它会以噗噗的效果消失吗?同样,在 Xcode 中,当您将断点拖到行号间距之外时,也会发生同样的情况。

我想在我的应用程序中实现相同的效果,但找不到正确的方法。

我有一个 NSImageView 后代来实现 NSDraggingSource 和 NSDraggingDestination 协议。我有这个视图的几个实例,它们允许在其他视图之间拖动它们的内容(在这种情况下会发生复制操作,但这仅与显示我已实现拖放并完全适用于标准任务有关)。

现在,当我将图像从其视图拖到任何地方(另一个视图实例除外)时,我希望删除操作在放置时进行。然而,拖动操作完全由目标视图控制。我可以设法让他们按照我想要的方式做出响应(尽管这将是很多工作),但如果我拖到我的应用程序之外,它会完全失败。

如果我可以获得删除拖动操作,我可以通过以下方式轻松处理这个问题:

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

(为简单起见,这是目前整个windw)。只要我不点击桌面或查找器窗口,它就可以工作。In 开始闪烁,可能是因为 Finder 同时设置了自己的拖动光标。当我到达码头时,它完全没有效果。当我定义自己的粘贴板数据类型时也会发生这种情况。

此外,我的应用程序中的任何其他启用拖放的视图仍将接受我不希望发生的拖动数据(例如 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 后代之外(在应用程序内部和外部)并没有给我 NSDragOperationDelete in draggedImage:endedAt:operation:(我在上面指定的),而是 NSDragOperationNone。此外,将鼠标移到应用程序外时的拖动光标是不允许的,而不是消失的项目。所以,如果有人能解决这两件事,我会接受它作为我问题的答案。

4

5 回答 5

2

可能有一种不那么老套的方法来做到这一点,但我可以想到一种可能性:一旦开始拖动,创建一个透明、无边框的窗口,其大小与桌面相同,作为虚拟拖动目标。您可能需要调用-setIgnoresMouseEvents:withNO以允许它接收丢弃,即使它是透明的。您还必须将其窗口级别设置在菜单栏上方(NSMainMenuWindowLevel + 1),以确保拖动到菜单栏或 Dock 时仍会被您的窗口拦截。

作为拖动目的地,此窗口必须检查您的图像视图之一是否在光标下。您可以使用+[NSWindow windowNumberAtPoint:belowWindowWithWindowNumber:]在光标下方的透明覆盖窗口下方找到窗口。然后用于-[NSApplication windowWithWindowNumber:]确定它是否是您的应用程序的窗口之一,如果是,则调用-[NSView hitTest:]其内容视图(根据需要转换光标坐标)以查找视图。然后,您可以NSDraggingDestination根据需要将方法转发到该视图。

于 2013-07-04T14:04:38.320 回答
2

我的猜测是 NSDragOperationDelete 仅涉及针对停靠栏 Trash的拖放操作,没有别的。

NSDragOperationGeneric应该更合适。确保不要混合方法,如果您要使用 10.7 路线,请首选:

-(void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation
于 2013-07-10T00:27:03.530 回答
1

我刚刚完成了与您所描述的非常相似的实现。您的代码与我的非常相似,但有一些例外:

你用的地方draggedImage:endedAt:operation:我用draggingSession:session:endedAt:operation:的。此外,在这种方法中,我不检查操作,因为我的所有操作都设置为generic. 这也是我执行实际删除的地方,所以如果删除成功,我只显示噗的动画。

在您的draggingSession:session:movedToPoint:中,您可能还希望将session's设置animatesToStartingPositionsOnCancelOrFailfalse当点在窗口外时(这也是您设置 的时候disappearingItemCursor),true否则设置为。这增加了最后一点,一旦删除操作完成,拖动的图像不会反弹回它的原始源位置。

至于为什么您没有看到正确的光标,我的猜测是您使用的是其他东西(Finder 等)愿意接受的粘贴板类型。我知道您说过您创建了自己的 Pastboard 数据类型,但我会仔细检查它们是否被使用。当我制作自己的类型时,我获得了对光标的控制权。至少,我没有找到任何与我的自定义类型竞争的东西。

于 2018-08-13T22:34:01.443 回答
0

OS X 10.7 or better:

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

This assumes that you have visually removed the object already. You could also set a flag during draggingEntered: and draggingExited: to indicate if drag session was last inside or outside of self.

In this program, leafs is the actual observed collection while visibleLeafs is a simulated collection of the representedObject of each visible control. Other NSDraggingDestination overloads present what will happen visually before it actually happens.

于 2014-02-20T00:43:42.770 回答
-3

您可以使用以下命令使 poof 出现在鼠标位置:

NSShowAnimationEffect(NSAnimationEffectPoof, [NSEvent mouseLocation], NSZeroSize, NULL, NULL, NULL);

有关详细信息,请参阅应用程序工具包功能参考

于 2013-05-13T08:43:39.090 回答