You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHPickerViewController选中照片预览无关闭按钮问题求助

问题解决

问题1:点击“显示已选(x)”无法关闭预览界面

这个问题源于已选资源列表变化时,PHPickerViewController的预选资源未同步更新,导致预览界面状态与实际选中状态不一致,无法触发关闭逻辑。需在updateUIViewController方法中同步更新picker的预选资源:

func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
    var assetIdentifiers = [String]()
    for asset in messageFormViewModel.photoPickerMedia {
        assetIdentifiers.append(asset.id)
    }
    // 更新picker的预选资源ID
    uiViewController.configuration.preselectedAssetIdentifiers = assetIdentifiers
}

同时修正picker(_:didFinishPicking:)中的逻辑:PHPicker返回的results是用户最终选择的完整列表,需先清空已选列表再添加新内容,避免重复或顺序混乱:

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    picker.dismiss(animated: true)
    
    // 清空原有已选内容,再添加新选择的资源
    parent.messageFormViewModel.photoPickerMedia.removeAll()
    
    for result in results {
        guard let id = result.assetIdentifier else {
            continue
        }
        
        let provider = result.itemProvider
        if provider.canLoadObject(ofClass: UIImage.self) {
            provider.loadObject(ofClass: UIImage.self) { image, _ in
                guard let image = image as? UIImage else { return }
                
                let viewModel = PhotoPickerViewModel(
                    id: id,
                    jpgData: image.jpegData(compressionQuality: 1.0)!,
                    image: image,
                    size: image.size
                )
                DispatchQueue.main.async {
                    self.parent.messageFormViewModel.photoPickerMedia.append(viewModel)
                }
            }
        }
    }
}

问题2:导航栏右侧存在不可见按钮

这是SwiftUI与UIKit导航栏交互的布局兼容性问题,可通过以下方式解决:

  1. 在makeUIViewController方法中设置picker的modal展示样式:
let picker = PHPickerViewController(configuration: config)
picker.delegate = context.coordinator
// 设置全屏展示,避免导航栏布局冲突
picker.modalPresentationStyle = .fullScreen
  1. 在SwiftUI中使用fullScreenCover而非sheet来present picker:
// 示例:在你的SwiftUI视图中触发picker
.fullScreenCover(isPresented: $showPicker) {
    PhotoPickerView(messageFormViewModel: yourViewModel)
}

完整修正代码

struct PhotoPickerView: UIViewControllerRepresentable {
    
    //MARK: - Properties
    @ObservedObject var messageFormViewModel: MessageFormViewModel // 外部传入的ViewModel需用@ObservedObject
    
    //MARK: - View
    func makeUIViewController(context: Context) -> PHPickerViewController {
        var assetIdentifiers = [String]()
        let photoLibrary = PHPhotoLibrary.shared()
        var config = PHPickerConfiguration(photoLibrary: photoLibrary)
        config.filter = .images
        config.selectionLimit = getAttachmentLimit()
        config.selection = .ordered
        for asset in messageFormViewModel.photoPickerMedia {
            assetIdentifiers.append(asset.id)
        }
        config.preselectedAssetIdentifiers = assetIdentifiers
        let picker = PHPickerViewController(configuration: config)
        picker.delegate = context.coordinator
        picker.modalPresentationStyle = .fullScreen
        return picker
    }

    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
        var assetIdentifiers = [String]()
        for asset in messageFormViewModel.photoPickerMedia {
            assetIdentifiers.append(asset.id)
        }
        uiViewController.configuration.preselectedAssetIdentifiers = assetIdentifiers
    }
    
    private func getAttachmentLimit() -> Int {
        guard let attachmentLimit = ApplicationSettingsManager.shared.settings?.limits.maxFileAttachments else {
            return 0
        }
        return attachmentLimit
    }

    //MARK: - Coordinator
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, PHPickerViewControllerDelegate {
        let parent: PhotoPickerView

        init(_ parent: PhotoPickerView) {
            self.parent = parent
        }

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)
            
            parent.messageFormViewModel.photoPickerMedia.removeAll()
            
            for result in results {
                guard let id = result.assetIdentifier else {
                    continue
                }
                
                let provider = result.itemProvider
                if provider.canLoadObject(ofClass: UIImage.self) {
                    provider.loadObject(ofClass: UIImage.self) { image, _ in
                        guard let image = image as? UIImage else { return }
                        
                        let viewModel = PhotoPickerViewModel(
                            id: id,
                            jpgData: image.jpegData(compressionQuality: 1.0)!,
                            image: image,
                            size: image.size
                        )
                        DispatchQueue.main.async {
                            self.parent.messageFormViewModel.photoPickerMedia.append(viewModel)
                        }
                    }
                }
            }
        }
    }
}

额外注意

  • 外部传入的ViewModel需使用@ObservedObject而非@StateObject,@StateObject仅适用于当前视图内部创建的ViewModel。

内容的提问来源于stack exchange,提问作者BrettS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 21:27:48