2019-02-28

macOS NSView 实现 drag and drop 拖放

Views: 10315 | Add Comments

macOS 实现 drag and drop 拖放很复杂,因为苹果的开发者中心把很多 demo 代码都不知道放到哪里去了,你用苹果开发者网站找不到 Sample Code,用 Xcode 帮助也没法找到(补充:sample code 在 https://developer.apple.com/library/archive/navigation/#section=Resource%20Types&topic=Sample%20Code )。而通过搜索引擎找的话,各种例子不是老旧就是没讲对。

其实 drag and drop 很简单。有两个概念:DraggingSource 和 DraggingDestination。你可以把拖放理解两个容器之间的交互,你要将某物从A拖到B然后放下。

最重要的一点,不管实现什么接口什么方法,你必须告诉系统什么时候拖放开始了。我看了很多文章,都没有重点提到这一点。也就是说,不管你实现什么接口都没有用,你必须主动告诉系统拖放已经开始了。所以,在你的代码中明确地告诉系统这一点,一般是鼠标按住的时候。

当你决定拖放已经开始了,就调用这个方法:

// NSView 的方法,当你决定 drag-n-drop 可以开始的时候,调用此方法
- (NSDraggingSession *)beginDraggingSessionWithItems:(NSArray *)items event:(NSEvent *)event source:(id)source;

调用这个方法之后,系统会自动地更新拖动过程的示意图的位置。当然,你要告诉系统示意图的开始位置和图片,通过上面的方法中的参数。另外,drag-n-drop 通过剪贴板在源和目的之间进行通信,所以剪贴板充当通信信道。下面的代码配置了通信信道和示意图:

// NSPasteboardItem 用于在 drag-n-drap 的双方之间进行通信
NSPasteboardItem *pbItem = [NSPasteboardItem new];
// 你可以直接传输数据, type 可自定义.
[pbItem setString:@"Transition" forType:NSPasteboardTypeString];
// 或者指定传输的数据由 NSPasteboardItemDataProvider 提供。
//[pbItem setDataProvider:self forTypes:@[NSPasteboardTypeString]];
// NSDraggingItem 用于显示 drag-n-drop 过程的示意图
NSDraggingItem *dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pbItem];
NSImage *img = [NSImage imageNamed:NSImageNameHomeTemplate];
NSRect frame = NSMakeRect(0, 0, img.size.width, img.size.height);
// draggingFrame 用于指定示意图的初始位置(在当前 NSView 中),contents 是示意图(NSImage)
[dragItem setDraggingFrame:frame contents:img];

这认为用网络通信模型来理解会更好,网络和通信是一个广义的概念,可以解释很多东西,我之前有文章介绍过:http://www.ideawu.net/blog/archives/528.html

弄明白了上面的之后,你再查看这几个接口就懂了:NSDraggingSource, NSDraggingDestination, NSPasteboardItemDataProvider

Related posts:

  1. NSView NSImage NSData转换
  2. 音频编码的一些笔记
  3. Xcode 静态链接库找不到的问题
  4. 轻量级 COMET 服务器 icomet 支持 EventSource(SSE)
  5. Cocoa 应用检测 ESC 按键
Posted by ideawu at 2019-02-28 19:52:20

Leave a Comment