【问题标题】:SwiftUI using NSSharingServicePicker in MacOS在 MacOS 中使用 NSSharingServicePicker 的 SwiftUI
【发布时间】:2020-03-31 13:56:47
【问题描述】:

我正在尝试在 SwiftUI 中的 MacOS 应用程序中使用共享功能。我有一个我想分享的文件的 URL。它可以是图像/文档等等。

我找到了适用于 MacOS 的 NSSharingServicePicker 并希望使用它。但是,我正在努力在 SwiftUI 中使用它。

按照文档,我是这样创建的:

let shareItems = [...]

let sharingPicker : NSSharingServicePicker = NSSharingServicePicker.init(items: shareItems as [Any])

sharingPicker.show(relativeTo: NSZeroRect, of:shareView, preferredEdge: .minY)

我的问题在于show() 方法。我需要设置一个 NSRect,我可以在其中使用 NSZeroRect.. 但我正在努力使用of: 参数。它需要一个 NSView。如何将当前视图转换为 NSView 并以这种方式使用它。或者我可以使用我的Button 作为NSView()。我正在为这种方法苦苦挣扎。

另一种选择是使用NSViewRepresentable。但是我应该只创建一个 NSView 并将其用于该方法。

【问题讨论】:

    标签: swift macos swiftui


    【解决方案1】:

    这是最小的工作演示示例

    struct SharingsPicker: NSViewRepresentable {
        @Binding var isPresented: Bool
        var sharingItems: [Any] = []
    
        func makeNSView(context: Context) -> NSView {
            let view = NSView()
            return view
        }
    
        func updateNSView(_ nsView: NSView, context: Context) {
            if isPresented {
                let picker = NSSharingServicePicker(items: sharingItems)
                picker.delegate = context.coordinator
    
                // !! MUST BE CALLED IN ASYNC, otherwise blocks update
                DispatchQueue.main.async {
                    picker.show(relativeTo: .zero, of: nsView, preferredEdge: .minY)
                }
            }
        }
    
        func makeCoordinator() -> Coordinator {
            Coordinator(owner: self)
        }
    
        class Coordinator: NSObject, NSSharingServicePickerDelegate {
            let owner: SharingsPicker
    
            init(owner: SharingsPicker) {
                self.owner = owner
            }
    
            func sharingServicePicker(_ sharingServicePicker: NSSharingServicePicker, didChoose service: NSSharingService?) {
    
                // do here whatever more needed here with selected service
    
                sharingServicePicker.delegate = nil   // << cleanup
                self.owner.isPresented = false        // << dismiss
            }
        }
    }
    

    使用演示:

    struct TestSharingService: View {
        @State private var showPicker = false
        var body: some View {
            Button("Share") {
                self.showPicker = true
            }
            .background(SharingsPicker(isPresented: $showPicker, sharingItems: ["Message"]))
        }
    }
    

    【讨论】:

    • 效果很好 :) 非常感谢.. 顺便问一下,您是否知道 Finder 中的“打开方式”上下文菜单是否可用?
    • @davidev 你找到方法了吗?
    • @Asperi 你有 Mac Catalyst 的代码吗?
    【解决方案2】:

    不使用NSViewRepresentable 的另一种选择是:

    extension NSSharingService {
        static func submenu(text: String) -> some View {
            return Menu(
                content: {
                    ForEach(items, id: \.title) { item in
                        Button(action: { item.perform(withItems: [text]) }) {
                            Image(nsImage: item.image)
                            Text(item.title)
                        }
                    }
                },
                label: {
                    Image(systemName: "square.and.arrow.up")
                }
            )
        }
    }
    

    您会丢失“更多”菜单项或最近的收件人等内容。但在我看来,简单纯粹的 SwiftUI 已经绰绰有余了。

    【讨论】:

      猜你喜欢
      • 2022-01-27
      • 2020-02-25
      • 2019-10-30
      • 1970-01-01
      • 1970-01-01
      • 2020-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多