拖动NSView时模拟“占位符”,并在用户取消拖动时避免闪烁

时间:2019-05-16 10:36:01

标签: cocoa drag-and-drop nsview nsdraggingitem

我有一个基本的Cocoa Mac应用程序,其视图包含一个子视图。可以在子视图中拖动子视图,我想通过在拖动时将占位符保留在其原始位置来给用户一种实际移动视图的印象。

默认方法是使用子视图的快照创建一个新的NSDraggingItem,以便在拖动视图时看起来确实在四处移动视图。

默认情况下,子视图在其初始位置仍然可见,因此屏幕上似乎有两个视图实例:

Default behavior

现在,我想给用户一种“拾取视图”并在将占位符保留在其初始位置的同时四处移动的错觉。我通过在拖动视图时将子视图的背景颜色更改为灰色来实现此目的。结果如下:

enter image description here

几乎完美!除了取消拖动并且视图移回其初始位置以外,它会闪烁一次。

那是因为我在NSDraggingSource.draggingSession(_ session: NSDraggingSession, endedAt screenPoint: NSPoint, operation: NSDragOperation)中还原了子视图的背景颜色,在拖动动画完成后,这又被称为很小的一部分。

这是事件的顺序:

  1. 用户开始拖动子视图
  2. 已拍摄视图快照并将其用于拖动会话
  3. 视图的背景颜色更改为深灰色,以模拟“占位符”
  4. 用户拖动视图并按Esc取消拖动
  5. 快照图像滑回到其初始位置
  6. 返回后,快照图像将在实际项目视图上方淡出(系统提供的动画)
  7. dragginSession(endedAt)被调用,背景变回

我的问题是我必须在#5之后而不是在#6之后恢复初始背景色。拖动动画快要结束时,有什么方法可以得到通知吗?

源代码:

class HomebaseView: NSView, NSDraggingSource {
    @IBOutlet var itemView:ItemView!

    override func mouseDragged(with event: NSEvent) {
        startDraggingItem(with: event)
    }

    func draggingSession(_ session: NSDraggingSession, willBeginAt screenPoint: NSPoint) {
        itemView.isBeingDragged = true
    }

    func draggingSession(_ session: NSDraggingSession, endedAt screenPoint: NSPoint, operation: NSDragOperation) {
        itemView.isBeingDragged = false
    }

    func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor context: NSDraggingContext) -> NSDragOperation {
        return .copy
    }

    private func startDraggingItem(with event:NSEvent) {
        let item = itemView!

        let pasteboardItem = NSPasteboardItem()

        let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem)

        let itemFrame = item.convert(item.bounds, to: self)

        draggingItem.setDraggingFrame(itemFrame, contents: item.snapshot())

        beginDraggingSession(with: [draggingItem], event: event, source: self)
    }
}
extension NSView {
    public func snapshot() -> NSImage {
        let pdfData = dataWithPDF(inside: bounds)
        let image = NSImage(data: pdfData)
        return image ?? NSImage()
    }
}

编辑:

为证明必须以某种方式实现这一点,这是Keynote中的动画。有点很难看,但是幻灯片“向后滑动”,而动画的原点却没有。

Keynote example

0 个答案:

没有答案