我有一个基本的Cocoa Mac应用程序,其视图包含一个子视图。可以在子视图中拖动子视图,我想通过在拖动时将占位符保留在其原始位置来给用户一种实际移动视图的印象。
默认方法是使用子视图的快照创建一个新的NSDraggingItem
,以便在拖动视图时看起来确实在四处移动视图。
默认情况下,子视图在其初始位置仍然可见,因此屏幕上似乎有两个视图实例:
现在,我想给用户一种“拾取视图”并在将占位符保留在其初始位置的同时四处移动的错觉。我通过在拖动视图时将子视图的背景颜色更改为灰色来实现此目的。结果如下:
几乎完美!除了取消拖动并且视图移回其初始位置以外,它会闪烁一次。
那是因为我在NSDraggingSource.draggingSession(_ session: NSDraggingSession, endedAt screenPoint: NSPoint, operation: NSDragOperation)
中还原了子视图的背景颜色,在拖动动画完成后,这又被称为很小的一部分。
这是事件的顺序:
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中的动画。有点很难看,但是幻灯片“向后滑动”,而动画的原点却没有。