【问题标题】:How to call PHPhotoLibrary presentLimitedLibraryPicker from SwiftUI?如何从 SwiftUI 调用 PHPhotoLibrary presentLimitedLibraryPicker?
【发布时间】:2020-09-13 11:32:19
【问题描述】:

从 SwiftUI 调用 PHPhotoLibrary 的 presentLimitedLibraryPicker 方法的正确方法是什么?

该方法需要一个 UIViewController,而我在 SwiftUI 中没有。

我尝试使用 UIViewControllerRepresentable 来创建 UIViewController,它可以工作,但结果是出现了两个视图控制器,一个是我使用 UIViewControllerRepresentable 创建的,一个是有限库选择器。

两个视图控制器都需要关闭才能进入原始屏幕,这是不可取的。

总结一下我看到的问题:

  1. presentLimitedLibraryPicker 通过传递 ViewController 来工作。
  2. 这让我创建并呈现了一个虚拟 ViewController,以便我可以调用该方法。
  3. 无法获得对有限库选择器的引用,它也不提供委托。所以我无法检测到 Limited Library Picker 控制器何时被解除。

这是我的尝试(它显示了选择器,但是当您关闭它时,您也需要关闭额外的虚拟视图控制器:

import Foundation
import SwiftUI
import Photos
import PhotosUI

struct TestView: View {

   @State var showLibraryPicker = false

var body: some View {
    NavigationView {
        VStack {
            Button("Open Library Picker") { showLibraryPicker = true }
        }
        .navigationBarTitle("Test", displayMode: .inline)
        .navigationViewStyle(StackNavigationViewStyle())
        .sheet(isPresented: $showLibraryPicker, onDismiss: { print("Dismissed") }) {
            TestLimitedLibraryPicker()
            }
        }
    }
}


struct TestLimitedLibraryPicker: UIViewControllerRepresentable {

     func makeUIViewController(context: Context) -> UIViewController {
         let controller = UIViewController()
         PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: controller)
          return controller
     }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {

     }
}

【问题讨论】:

  • 你会展示你的代码吗?
  • @Asperi 我已经添加了示例代码,谢谢!

标签: ios swiftui photosui


【解决方案1】:

这是一些演示方法。使用 Xcode 12 / iOS 14 准备和测试。

struct TestPhotosView: View {

    @State var showLibraryPicker = false

    var body: some View {
        NavigationView {
            VStack {
                Button("Open Library Picker") { self.showLibraryPicker = true }
            }
            .navigationBarTitle("Test", displayMode: .inline)
            .navigationViewStyle(StackNavigationViewStyle())
            .background(Group {
                if self.showLibraryPicker {
                    TestLimitedLibraryPicker(isPresented: $showLibraryPicker)
                }
            })
        }
    }
}


struct TestLimitedLibraryPicker: UIViewControllerRepresentable {
    @Binding var isPresented: Bool

    func makeUIViewController(context: Context) -> UIViewController {
        let controller = UIViewController()

        DispatchQueue.main.async {
            PHPhotoLibrary.requestAuthorization() { result in
                PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: controller)
                context.coordinator.trackCompletion(in: controller)
            }
        }
        
        return controller
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}

    func makeCoordinator() -> Coordinator {
        Coordinator(isPresented: $isPresented)
    }
    class Coordinator: NSObject {
        private var isPresented: Binding<Bool>
        init(isPresented: Binding<Bool>) {
            self.isPresented = isPresented
        }

        func trackCompletion(in controller: UIViewController) {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self, weak controller] in
                if controller?.presentedViewController == nil {
                    self?.isPresented.wrappedValue = false
                } else if let controller = controller {
                    self?.trackCompletion(in: controller)
                }
            }
        }
    }
}

【讨论】:

  • 谢谢!它确实有效,尽管与 SwiftUI 处理其他事情的方式相比,跟踪控制器是否被解雇的方式感觉有点“脏”。我希望在未来我们将在 PhotosUI 和 SwiftUI 之间进行更好的集成。
【解决方案2】:

刚遇到这个问题!这是我的看法。

  • 没有 SwiftUI 方法来调用有限的照片选择器。所以我们必须创建一个调用.presentLimitedLibraryPicker的视图控制器(UIViewControllerRepresentable)。但是,如果您将此作为工作表呈现,它将立即显示选择器,并且您会在工作表上获得一张工作表。
  • 取而代之的是,将包装好的 View Controller直接嵌入到 View 的主体中,并将绑定传递给条件触发器。
  • 在包装好的视图控制器中,寻找对updateUIViewController 中条件的更改。如果值为true,请出示选择器,然后立即关闭该值。
import SwiftUI
import UIKit
import PhotosUI

struct ContainingView: View {
    @State var showLimitedPicker: Bool = false

    var body: some View {
        HStack {
            Button("Load more…") { showLimitedPicker = true }
            LimitedPicker(isPresented: $showLimitedPicker)
                .frame(width: 0, height: 0)
        }
    }
}

struct LimitedPicker: UIViewControllerRepresentable {
    @Binding var isPresented: Bool

    func makeUIViewController(context: Context) -> UIViewController {
        UIViewController()
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        if isPresented {
            PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: uiViewController)
            DispatchQueue.main.async {
                isPresented = false
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-03
    • 1970-01-01
    相关资源
    最近更新 更多