我正在使用UIImagePickerController从用户的照片库中选择图像。除了用户用放大镜图标点击字段以搜索库时,所有操作都很好。有时它会解雇ImagePicker,有时它什么也不做,偶尔它会像预期的那样工作。。。有什么想法吗?
显示工作表的代码:
Button(action: {}) {
ZStack {
Image(systemName: "photo")
.foregroundColor(darkMode ? .white : .black)
}
}
.frame(width: 44, height: 44)
.onTapGesture {
showPhotoLibrary.toggle()
}
.sheet(isPresented: $showPhotoLibrary) {
ImagePicker(sourceType: .photoLibrary, selectedImage: self.$image)
}
ImagePicker:
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
var sourceType: UIImagePickerController.SourceType = .photoLibrary
@Binding var selectedImage: UIImage
@Environment(.presentationMode) private var presentationMode
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
imagePicker.sourceType = sourceType
imagePicker.delegate = context.coordinator
return imagePicker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
internal func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
parent.selectedImage = image
}
parent.presentationMode.wrappedValue.dismiss()
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
我见过很多人为此而挣扎,苹果开发论坛上到处都是,所以我想我会尝试解决它。从我自己的测试来看,我认为问题的原因是UIImagePickerController
被设计为使用父视图控制器的present
方法来呈现,而不是用作SwiftUI呈现的工作表的根视图控制器,就像苹果(在他们的示例代码中(和其他人似乎正在做的那样。下面是我不完整的测试代码,它显示了一个正在工作的图像选择器,它可以在哪里进行搜索,也可以向下拖动以忽略它,所以我认为这可能是正确的解决方案。
其思想是,我们使用UIViewControllerRepresentable
来呈现我们自己的自定义视图控制器,当当前布尔值发生变化时,该控制器会显示或取消图像选择器视图控制器。
struct ImagePickerTest: View {
@State var show = false
@State var image1: UIImage?
var body: some View {
VStack {
Button("Hello, World!") {
show.toggle()
}
Text("image: (image1?.description ?? "" )")
}
.imagePicking(isPresented: $show, selectedImage: $image1)
}
}
extension View {
// this could be refactored into a `ViewModifier`
func imagePicking(isPresented: Binding<Bool>, selectedImage: Binding<UIImage?>) -> some View {
ZStack {
ImagePicking(isPresented: isPresented, selectedImage: selectedImage)
self
}
}
}
class MyViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate{
var dismissPicker: (() -> Void)?
var selectImage: ((UIImage) -> Void)?
func showPickerIfNecessary() {
if self.presentedViewController != nil {
return
}
let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
present(imagePickerController, animated: true)
}
func hidePickerIfNecessary() {
if let vc = self.presentedViewController {
vc.dismiss(animated: true)
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
print("imagePickerControllerDidCancel")
dismissPicker?()
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
print("didFinishPickingMediaWithInfo")
if let image = (info[.editedImage] ?? info[.originalImage]) as? UIImage {
selectImage?(image)
dismissPicker?()
}
}
}
struct ImagePicking: UIViewControllerRepresentable {
@Binding var isPresented: Bool
@Binding var selectedImage: UIImage?
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
uiViewController.dismissPicker = {
isPresented = false
}
uiViewController.selectImage = { image in
selectedImage = image
}
if isPresented {
uiViewController.showPickerIfNecessary()
} else {
uiViewController.hidePickerIfNecessary()
}
}
func makeUIViewController(context: Context) -> some MyViewController {
MyViewController()
}
}
在我开始之前,我验证了OP的代码在键入搜索时失败,它崩溃了,出现了以下错误:
2022-08-31 22:39:17.808899+0100 Test[66967:5425868] [UI] -[PUPhotoPickerHostViewController viewServiceDidTerminateWithError:] Error Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}