我有一个自定义集合视图:
import AppKit
final class InternalCollectionView: NSCollectionView {
typealias KeyDownHandler = (_ event: NSEvent) -> Bool
var keyDownHandler: KeyDownHandler? = nil
// Do nothing on Cmd+A
override func selectAll(_ sender: Any?) { }
}
我也有SwiftUI的collectionView,里面使用了一些控制器:
struct FBCollectionView<Content: View>: NSViewControllerRepresentable {
//here some implementation
}
public class NSCollectionController<Content: View>: NSViewController, NSCollectionViewDelegate, NSCollectionViewDataSource, QLPreviewPanelDataSource, QLPreviewPanelDelegate {
//here some implementation
}
我需要实现逻辑:
- 拖动的项目必须在它们的位置上绘制,但不能隐藏[完成]
- 应用程序必须隐藏在应用程序外部拖动
首先,我已经试图只是隐藏应用程序上拖动开始.为此,我实现了NSCollectionController
的方法:
public func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, willBeginAt screenPoint: NSPoint, forItemsAt indexPaths: Set<IndexPath>) {
hideApp()
preventHidingItemsDuringDrag(collectionView, indexPaths: indexPaths)
}
func hideApp() {
DispatchQueue.main.async {
NSApplication.shared.hide(self)
}
appShown = false
automaticScroller.updStatus(appDisplayed: appShown)
}
但由于某种原因,这只适用于第一次拖动(!)在每个以下拖动应用程序不隐藏
我试图在主线程中运行此代码,但没有得到任何可用的结果
所以问题是
- 如何在应用程序外部拖动时隐藏应用程序?
2条答案
按热度按时间s4n0splo1#
您可以考虑使用
addLocalMonitorForEvents
(我考虑过addGlobalMonitorForEvents
,但是...如此处所示,应用程序需要具有可访问性访问权限)然而,正如执行部分在评论中指出的:
只有在释放鼠标按钮后才隐藏应用程序。出于某种原因,collectionView保存了窗口的绘制(在我的例子中是NSPanel)。hideApp()只有在我放下鼠标按钮之后才被调用(我在日志中看到了这一点)
因此,让我们尝试另一个来监视拖动会话状态。
阅读“Supporting Table View Drag and Drop Through File Promises”,我明白了:
当拖动开始时,采用
NSPasteboardWriting
协议将数据写入NSPasteboard
。拖动时,确定有效的放置目标。当拖动结束时,您将从NSPasteboard
读取拖动数据。”注意到了:
NSCollectionController
类是NSCollectionView
的控制器。它处理许多任务,包括充当集合视图的委托和数据源,以及管理拖放交互。为了在拖动项目移出应用程序窗口时隐藏整个应用程序,我们的想法是使用一个符合
NSPasteboardWriting
和NSDraggingSource
协议的自定义类(MyPasteboardWriter
)。NSPasteboardWriting
协议允许类向粘贴板(在拖放操作期间使用)提供数据,而NSDraggingSource
允许它对拖放事件做出React。在
NSDraggingSource
协议中,实现draggingSession(_:movedTo:)
方法来检查拖动项的位置。如果该项移动到应用程序窗口之外,则应用程序将被隐藏。这是通过使用NSApplication.shared.hide(nil)
函数来完成的。appShown
静态变量用于跟踪应用程序当前是否可见。防止应用程序连续多次尝试隐藏非常重要。draggingSession(_:sourceOperationMaskFor:)
方法还用于指定在源应用程序外部拖动时允许的操作(.copy,.move)。最后,
collectionView(_:draggingSession:endedAt:dragOperation:)
delegate方法用于在拖动会话结束时将appShown
标志重置回true,表示现在可以再次显示应用程序。movedTo
函数从未调用,因此无法隐藏应用程序。MyPasteboardWriter
作为其粘贴板编写器。NSDraggingSource
协议并实现draggingSession(_:movedTo:)
方法的类必须是在启动拖动会话时用作源对象的类。如果使用其他对象作为源,则不会调用该方法。
frebpwbc2#
我不认为在拖动过程中隐藏应用程序会起作用。可以隐藏窗口。
子类
NSCollectionView
并覆盖func draggingSession(_ session: NSDraggingSession, movedTo screenPoint: NSPoint)
。当screenPoint
在窗口外时隐藏窗口。