bounty还有5天到期。回答此问题可获得+300声望奖励。Andrew_STOP_RU_WAR_IN_UA希望引起更多关注这个问题。
我有一个自定义集合视图:
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)
}
但由于某种原因,这只适用于第一次拖动(!)在每个以下拖动应用程序不隐藏
我试图在主线程中运行此代码,但没有得到任何可用的结果
所以问题是
- 如何在应用程序外部拖动时隐藏应用程序?
1条答案
按热度按时间q3qa4bjr1#
您可以考虑使用
addLocalMonitorForEvents
(我考虑过addGlobalMonitorForEvents
,但是...如此处所示,应用程序需要具有可访问性访问权限)然而,正如执行部分在评论中指出的:
只有在释放鼠标按钮后才隐藏应用程序。出于某种原因,collectionView保存了窗口的绘制(在我的例子中是NSPanel)。hideApp()只有在我放下鼠标按钮之后才被调用(我在日志中看到了这一点)
因此,让我们尝试另一个来监视拖动会话状态。
首先,更新您的
NSCollectionController
以符合NSDraggingSource
。该协议有一个方法draggingSession(_:movedTo:)
,每当拖动项移动时都会调用该方法。它提供了拖动项的屏幕点,您可以使用该点来检测该项是否已被拖动到应用程序窗口之外。下面是一个例子:
在本例中,我们将
self
(NSCollectionController
)指定为collectionView(_:draggingSession:willBeginAt:forItemsAt:)
方法中的拖动源。这允许每当拖动项被移动时调用draggingSession(_:movedTo:)
方法。然后,在
draggingSession(_:movedTo:)
方法中,我们获取屏幕坐标中的窗口框架,并检查新的鼠标位置(screenPoint
参数)是否在该框架之外。如果是,则调用hideApp()
方法。这种方法应该在拖动项移出窗口后立即隐藏应用程序,并且不需要更改任何系统安全设置。
至于第一次拖动后每次鼠标移动时应用程序都会隐藏的问题,这可能是因为即使您没有拖动任何东西,也会调用
hideApp()
方法。若要避免这种情况,请确保仅在拖动会话处于活动状态时隐藏应用。您可以通过在调用hideApp()
之前检查isDragging
标志来实现这一点。例如:
请记住,在拖动会话开始时将
isDragging
设置为true
,在拖动会话结束时将false
设置为false
。完整代码:
在
collectionView(_:draggingSession:willBeginAt:forItemsAt:)
方法中,我们将isDragging
设置为true
,并将self
设置为拖动源。在
draggingSession(_:movedTo:)
方法中,我们检查拖动的项是否已移动到窗口之外。如果有,我们调用hideApp()
。最后,在
collectionView(_:draggingSession:endedAt:dragOperation:)
方法中,我们将isDragging
设置为false
以指示拖动会话已经结束。这应确保当您将项目拖动到应用程序窗口外时,应用程序处于隐藏状态,并且在拖动操作结束后简单移动鼠标时,应用程序不会隐藏。