如何从 SwiftUI 调用 PHPhotoLibrary presentLimitedLibraryPicker?
Posted
技术标签:
【中文标题】如何从 SwiftUI 调用 PHPhotoLibrary presentLimitedLibraryPicker?【英文标题】:How to call PHPhotoLibrary presentLimitedLibraryPicker from SwiftUI? 【发布时间】:2020-09-13 11:32:19 【问题描述】:从 SwiftUI 调用 phphotoLibrary 的 presentLimitedLibraryPicker 方法的正确方法是什么?
该方法需要一个 UIViewController,而我在 SwiftUI 中没有。
我尝试使用 UIViewControllerRepresentable 来创建 UIViewController,它可以工作,但结果是出现了两个视图控制器,一个是我使用 UIViewControllerRepresentable 创建的,一个是有限库选择器。
两个视图控制器都需要关闭才能进入原始屏幕,这是不可取的。
总结一下我看到的问题:
-
presentLimitedLibraryPicker 通过传递 ViewController 来工作。
这让我创建并呈现了一个虚拟 ViewController,以便我可以调用该方法。
无法获得对有限库选择器的引用,它也不提供委托。所以我无法检测到 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 我已经添加了示例代码,谢谢! 【参考方案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
【讨论】:
以上是关于如何从 SwiftUI 调用 PHPhotoLibrary presentLimitedLibraryPicker?的主要内容,如果未能解决你的问题,请参考以下文章