首页 > 解决方案 > 如何处理拖到 SwiftUI 中的停靠图标上?

问题描述

我已经设置了一个 SwiftUI 应用程序,该应用程序似乎接受拖放到停靠图标上的图像,但我无法弄清楚在我的应用程序代码中处理拖放图像的位置。

如何处理将图像(或任何特定文件)拖放到 SwiftUI 应用程序的停靠图标上?

背景

使用使用 NSApplication 的旧式 Swift 代码,处理应用程序停靠图标上的文件删除可以分两步完成:

  1. 在 Info.plist 的 CFBundleDocumentTypes 中注册要接受的类型。
  2. 在你的 NSApplicationDelegate 上实现application:openFile:(可能还有 application:openFiles:)。

这在一个单独的问题中简洁地记录了下来。

在 Swift UI 中创建应用程序委托(不起作用)

不过,SwiftUI 应用默认不提供应用委托。要实现这些功能,您必须做一些额外的工作

  1. 创建一个实现NSObjectNSApplicationDelegate(或UIApplicationDelegate)的类:

    // or NSApplicationDelegate
    class AppDelegate: NSObject, UIApplicationDelegate {
       // ...
    }
    
  2. 在您的@main App实现中,设置委托:

    ... : App {
        // or @NSApplicationDelegateAdaptor
        @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    

您现在可以实现应用程序委托方法!例如,这将在您的应用启动时打印:

func applicationWillFinishLaunching(_ notification: Notification) {
    print("App Delegate loaded!")
}

但是实现 openFile 函数不起作用:

func application(_ sender: NSApplication, openFile filename: String) -> Bool {
    print("test", filename)
    return false
 }
    
func application(_ sender: NSApplication, openFiles filenames: [String]) {
     print("another test", filenames)
}

将文件拖到应用程序上时,这些都不会打印出来。

场景代表?

这似乎是将 AppDelegate 功能分离到 SceneDelegate 中的一些工作的结果:

对于那些可能对此感到头疼的人来说,由于 appdelegate 的功能分离,现在在场景委托中调用了等效的功能。 等效的函数是 scene(_ scene: openURLContexts:)。我还没有研究是否可以“选择退出”,但出于我的目的,没有理由不采用新行为

— m_bedwell on application(open: options:) 没有被调用(强调)

但是没有明显的方法可以访问我们的代码的 SceneDelegate(这甚至可能不适用于 macOS?)。有一个很有希望的类似问题

有没有更好的办法?

标签: swiftmacosswiftui

解决方案


在 SwiftUI 中有一种非常简单的方法可以处理拖放到 Dock 图标上!

  1. 更新您的 Info.plist 以指示您的应用程序支持您想要的文件类型(就像在旧应用程序中一样):

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <!-- ... -->
        <key>CFBundleTypeName</key>
        <string>Image files</string>
        <key>CFBundleTypeRole</key>
        <string>Viewer</string>
        <key>LSHandlerRank</key>
        <string>Default</string>
        <key>LSItemContentTypes</key>
        <array>
            <string>public.image</string>
        </array>
    </dict>
    </plist>
    
  2. 在您body的中App,使用onOpenURL

    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL { (url) in
                    // Handle url here
                }
        }
    }
    

— ianivs(如何使用新的 SwiftUI @main 启动处理 URL 回调?


推荐阅读