35

macOS NSView 实现 drag and drop 拖放

 5 years ago
source link: http://www.ideawu.net/blog/archives/1058.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

macOS 实现 drag and drop 拖放很复杂,因为苹果的开发者中心把很多 demo 代码都不知道放到哪里去了,你用苹果开发者网站找不到 Sample Code,用 Xcode 帮助也没法找到。而通过搜索引擎找的话,各种例子不是老旧就是没讲对。

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

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

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

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

 </nsdraggingsource>
</nsdraggingitem>

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

// NSPasteboardItem 用于在 drag-n-drap 的双方之间进行通信
NSPasteboardItem *pbItem = [NSPasteboardItem new];
// 指定要传输的数据类型,最后要传输的数据由 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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK