首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SwiftUI拖放文件

SwiftUI拖放文件
EN

Stack Overflow用户
提问于 2020-03-24 12:41:46
回答 3查看 9.9K关注 0票数 13

我正在尝试向我的SwiftUI Mac应用程序添加一个“拖放”手势/函数。

我想把文件从我的系统/桌面放到我的应用程序中。我发现它属于普通的Swift公司。我现在正试着用SwiftUI来做这个。

我在onDrop()中为视图找到了一个SwiftUI函数。但是,看起来这只适用于我的应用程序中的内部手势。我想从外面拖文件。

在Swift中,您需要注册您的NSView,用于拖动类型。

代码语言:javascript
复制
registerForDraggedTypes([kUTTypeFileURL,kUTTypeImage])

我想创建一个NSViewRepresentable并将其包装到我的SwiftUI视图中。

这是我想出的代码,但是我不能调用registerForDraggedTyped

代码语言:javascript
复制
final class DragDropView: NSViewRepresentable {

    func makeNSView(context: NSViewRepresentableContext<DragDropView>) -> NSView {
        let view = NSView()

        view.registerForDraggedTypes([NSPasteboard.PasteboardType.pdf, NSPasteboard.PasteboardType.png])

        return view
    }

    func updateNSView(_ nsView: NSView, context: NSViewRepresentableContext<DragDropView>) {

    }

在SwiftUI中有更简单的解决方案吗?我很想使用这个onDrop()函数,但是这并不适用于外部文件,对吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-03-24 14:05:33

下面是一个拖放演示,用Xcode 11.4 / macOS 10.15.4进行测试。

初始image位于资产库上,接受从Finder/Desktop ( drop )到TextEdit (拖放)的文件url (仅为简单起见),并为TIFF表示拖动寄存器。

代码语言:javascript
复制
struct TestImageDragDrop: View {
    @State var image = NSImage(named: "image")
    @State private var dragOver = false

    var body: some View {
        Image(nsImage: image ?? NSImage())
            .onDrop(of: ["public.file-url"], isTargeted: $dragOver) { providers -> Bool in
                providers.first?.loadDataRepresentation(forTypeIdentifier: "public.file-url", completionHandler: { (data, error) in
                    if let data = data, let path = NSString(data: data, encoding: 4), let url = URL(string: path as String) {
                        let image = NSImage(contentsOf: url)
                        DispatchQueue.main.async {
                            self.image = image
                        }
                    }
                })
                return true
            }
            .onDrag {
                let data = self.image?.tiffRepresentation
                let provider = NSItemProvider(item: data as NSSecureCoding?, typeIdentifier: kUTTypeTIFF as String)
                provider.previewImageHandler = { (handler, _, _) -> Void in
                    handler?(data as NSSecureCoding?, nil)
                }
                return provider
            }
            .border(dragOver ? Color.red : Color.clear)
    }
}
票数 35
EN

Stack Overflow用户

发布于 2020-07-03 06:12:44

正如OP所指出的,对于Mac应用程序,这是仅限

如果你想

  1. 从Finder打开
  2. 从查找器拖动
  3. 并从其他地方拖动(如网站或iMessage)

然后尝试以下操作(从此视图拖动图像不包括在内)。

XCode 11+ / SwiftUI 1.0+ / Swift 5:

从Finder处打开所需的分机:

代码语言:javascript
复制
extension NSOpenPanel {
    
    static func openImage(completion: @escaping (_ result: Result<NSImage, Error>) -> ()) {
        let panel = NSOpenPanel()
        panel.allowsMultipleSelection = false
        panel.canChooseFiles = true
        panel.canChooseDirectories = false
        panel.allowedFileTypes = ["jpg", "jpeg", "png", "heic"]
        panel.canChooseFiles = true
        panel.begin { (result) in
            if result == .OK,
                let url = panel.urls.first,
                let image = NSImage(contentsOf: url) {
                completion(.success(image))
            } else {
                completion(.failure(
                    NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to get file location"])
                ))
            }
        }
    }
}

SwiftUI视图

代码语言:javascript
复制
struct InputView: View {
    
    @Binding var image: NSImage?
    
    var body: some View {
        VStack(spacing: 16) {
            HStack {
                Text("Input Image (PNG,JPG,JPEG,HEIC)")
                Button(action: selectFile) {
                    Text("From Finder")
                }
            }
            InputImageView(image: self.$image)
        }
    }
    
    private func selectFile() {
        NSOpenPanel.openImage { (result) in
            if case let .success(image) = result {
                self.image = image
            }
        }
    }
}

struct InputImageView: View {
    
    @Binding var image: NSImage?
        
    var body: some View {
        ZStack {
            if self.image != nil {
                Image(nsImage: self.image!)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
            } else {
                Text("Drag and drop image file")
                    .frame(width: 320)
            }
        }
        .frame(height: 320)
        .background(Color.black.opacity(0.5))
        .cornerRadius(8)
            
        .onDrop(of: ["public.url","public.file-url"], isTargeted: nil) { (items) -> Bool in
            if let item = items.first {
                if let identifier = item.registeredTypeIdentifiers.first {
                    print("onDrop with identifier = \(identifier)")
                    if identifier == "public.url" || identifier == "public.file-url" {
                        item.loadItem(forTypeIdentifier: identifier, options: nil) { (urlData, error) in
                            DispatchQueue.main.async {
                                if let urlData = urlData as? Data {
                                    let urll = NSURL(absoluteURLWithDataRepresentation: urlData, relativeTo: nil) as URL
                                    if let img = NSImage(contentsOf: urll) {
                                        self.image = img
                                        print("got it")
                                    }
                                }
                            }
                        }
                    }
                }
                return true
            } else { print("item not here") return false }
        }
    }    
}

注意:不需要使用"public.image“标识符。

如果需要作为PNG数据的结果(我确实上传到Firebase存储),可以选择扩展:

代码语言:javascript
复制
extension NSBitmapImageRep {
    var png: Data? { representation(using: .png, properties: [.compressionFactor:0.05]) }
}

extension Data {
    var bitmap: NSBitmapImageRep? { NSBitmapImageRep(data: self) }
}

extension NSImage {
    var png: Data? { tiffRepresentation?.bitmap?.png }
}

// usage

let image = NSImage(...)
if let data = image.png {
     // do something further with the data
}
票数 13
EN

Stack Overflow用户

发布于 2020-03-24 12:53:19

你不能用onDrop(of:isTargeted:perform:)吗?可以在of参数中传递受支持类型的数组。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60831260

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档