问题描述
可以将 vc 推送到 PHPickerViewController 上吗?
我正在尝试这样做,但没有运气:
var configuration = PHPickerConfiguration()
configuration.filter = .any(of: [.images,.livePhotos])
photoPickerController = PHPickerViewController(configuration: configuration)
photoPickerController.delegate = self
present(self.photoPickerController,animated: true)
func picker(_ picker: PHPickerViewController,didFinishPicking results: [PHPickerResult]) {
//Push segue
performSegue(withIdentifier: "showAddPost",sender: self)
}
解决方法
更新 - 使用 CocoaPods
我创建了一个简单的 pod PhotoCropController,其中包含一个从 PHPickerViewControllerDelegate 呈现的基本照片裁剪控制器。它提供转换以推送到模态呈现的控制器以及弹出或关闭。裁剪视图的纵横比也可以编辑。使用使您的视图控制器符合 PhotoCropDelegate 协议并从您的 PHPickerViewControllerDelegate 呈现 PhotoCropController。实现将类似于以下内容:
extension ViewController: PHPickerViewControllerDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,PhotoCropDelegate {
func browsePhotoLibrary() {
if #available(iOS 14,*) {
var config = PHPickerConfiguration()
config.filter = PHPickerFilter.images
config.selectionLimit = 1
config.preferredAssetRepresentationMode = .compatible
let picker = PHPickerViewController(configuration: config)
picker.delegate = self
let nav = UINavigationController(rootViewController: picker)
nav.setNavigationBarHidden(true,animated: false)
nav.setToolbarHidden(true,animated: true)
present(nav,animated: true) } else {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = true
present(picker,animated: true)
}
}
func imagePickerController(_ picker: UIImagePickerController,didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let edited = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
image = edited
} else if let selected = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
image = selected
}
presentedViewController?.dismiss(animated: true)
}
@available(iOS 14,*)
func picker(_ picker: PHPickerViewController,didFinishPicking results: [PHPickerResult]) {
if let provider = results.last?.itemProvider,provider.canLoadObject(ofClass: UIImage.self) {
provider.loadObject(ofClass: UIImage.self) { [weak self] result,error in
if let image = result as? UIImage {
DispatchQueue.main.async { self?.select(image: image) }
} else if let error = error {
NSLog("Error picking image: %@",error.localizedDescription)
DispatchQueue.main.async { picker.dismiss(animated: true) }
}
}
} else { DispatchQueue.main.async { picker.dismiss(animated: true) } }
}
func select(image: UIImage) {
let destinationSize = AVMakeRect(aspectRatio: image.size,insideRect: view.frame).integral.size
//Best Performance
let resizedImage = UIGraphicsImageRenderer(size: destinationSize).image { (context) in
image.draw(in: CGRect(origin: .zero,size: destinationSize))
}
let cropController = PhotoCropController()
cropController.delegate = self
cropController.image = resizedImage
presentedViewController?.present(cropController,animated: true)
}
@objc func cropViewDidCrop(image: UIImage?) {
self.image = image
presentedViewController?.dismiss(animated: true) { [weak self] in
self?.presentedViewController?.dismiss(animated: true)
}
}
}
在 PHPickerViewController 前面模态地呈现另一个控制器:
您的视图控制器的presentedViewController 属性将是您的photoPickerController,因此您可以在其前面显示另一个控制器,如下所示:
present(photoPickerController,animated: true)
presentedViewController?.present(yourViewController,animated: true)
如果从presentedViewController中解散,你需要调用两次,一次解散你的ViewController,然后再次解散photoPickerController,如果它们都被呈现:
presentedViewController?.dismiss(animated: true)
presentedViewController?.dismiss(animated: true)
将自定义控制器推送到导航堆栈顶部
要创建推送到 PHPickerViewController 堆栈的外观,您可以使用自定义 UIPresentationController 和 UIViewControllerAnimatedTransitioning 类来呈现您的视图。以下类将模拟对模态呈现的导航控制器的推送:
import UIKit
import PhotosUI
class SlideInModalPresentationController: UIPresentationController {
var offset: CGFloat = 0.0
override func containerViewWillLayoutSubviews() {
super.containerViewWillLayoutSubviews()
presentedView?.frame.origin.y = offset
presentedView?.frame.size.height -= offset
presentedView?.layer.cornerRadius = 10
presentedView?.clipsToBounds = true
}
}
class SlideInTransition: NSObject,UIViewControllerAnimatedTransitioning {
private let duration = 0.3
var isPresenting: Bool = true
var dismissModally: Bool = false
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let toController = transitionContext.viewController(forKey: .to),let fromController = transitionContext.viewController(forKey: .from)
else { return}
if isPresenting {
toController.view.frame.origin.x = fromController.view.frame.width
transitionContext.containerView.addSubview(toController.view)
UIView.animate(withDuration: duration,animations: {
toController.view.frame.origin.x = 0
},completion: { _ in
transitionContext.completeTransition(true)
})
} else if dismissModally {
var stack: UIView? = nil
if #available(iOS 14,*),toController is PHPickerViewController {
stack = toController.view.superview
toController.dismiss(animated: false)
} else if toController is UIImagePickerController {
stack = toController.view.superview
toController.dismiss(animated: false)
}
UIView.animate(withDuration: duration,animations: {
stack?.frame.origin.y = fromController.view.frame.height
fromController.view.frame.origin.y = fromController.view.frame.height
},completion: { _ in
transitionContext.completeTransition(true)
fromController.view.removeFromSuperview()
})
} else {
UIView.animate(withDuration: duration,animations: {
fromController.view.frame.origin.x = fromController.view.frame.width
},completion: { _ in
transitionContext.completeTransition(true)
fromController.view.removeFromSuperview()
})
}
}
}
在你的视图控制器中实现:
class ViewController: UIViewController {
let slidInTransition = SlideInTransition()
}
extension ViewController: UIViewControllerTransitioningDelegate {
private func presentYourController(_ image: UIImage) {
let yourController = YourController()
yourController.image = image
yourController.modalPresentationStyle = .custom
yourController.transitioningDelegate = self
slidInTransition.dismissModally = false
presentedViewController?.present(yourController,animated: true)
}
func presentationController(forPresented presented: UIViewController,presenting: UIViewController?,source: UIViewController) -> UIPresentationController? {
let presentationController = SlideInModalPresentationController(presentedViewController: presented,presenting: presenting)
presentationController.offset = view.convert(source.view.frame,to: nil).origin.y + 10
return presentationController
}
func animationController(forPresented presented: UIViewController,presenting: UIViewController,source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
slidInTransition.isPresenting = true
return slidInTransition
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
slidInTransition.isPresenting = false
return slidInTransition
}
private func dismissPhotoStack() {
slidInTransition.dismissModally = true
presentedViewController?.dismiss(animated: true)
}
}
当您准备关闭整个堆栈时,您可以调用dismissPhotoStack。