UIImagePicker控制器裁剪图像矩形不正确



我有一个保存图像选择器的UIViewController

let picker = UIImagePickerController()

我这样称呼图像选择器:

private func showCamera() {
picker.allowsEditing = true
picker.sourceType = .camera
picker.cameraCaptureMode = .photo
picker.modalPresentationStyle = .fullScreen
present(picker, animated: true, completion: nil)
}

完成后,我会收到这样的委托回调:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
DispatchQueue.main.async {
if let croppedImage = info[UIImagePickerControllerEditedImage] as? UIImage {
self.imageView.contentMode = .scaleAspectFill
self.imageView.image = croppedImage
self.dismiss(animated:true, completion: nil)
}
}
}

拍摄图像后,我得到了裁剪 UI,在视频中您可以看到行为:

https://youtu.be/OaJnsjrlwF8

如您所见,我无法将缩放的矩形滚动到底部或顶部。此行为可在多个设备上的iOS 10/11上重现。

有没有办法用UIImagePickerController做到这一点?

不,这个组件已经被窃听了很长时间了。不仅这个有定位的矩形,而且裁剪的矩形通常不正确(垂直偏差约20px)。

苹果似乎没有兴趣修复它,你应该创建自己的。这不是太多的工作。首先创建一个屏幕,该屏幕接受并在滚动视图上显示图像。然后确保缩放和平移正常工作(甚至旋转),这应该很快完成。

然后发生裁剪部分,这实际上是使用视图快照完成的最快:

以下内容将从图像视图创建图像:

func snapshotImageFor(view: UIView) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
view.layer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}

然后在视图控制器中,您可以执行此小技巧:

func createSnapshot(inFrame rect: CGRect) -> UIImage? {
let temporaryView = UIView(frame: rect) // This is a view from which the snapshot will occure
temporaryView.clipsToBounds = true
view.addSubview(temporaryView) // We want to put it into hierarchy
guard let viewToSnap = scrollViewContainer else { return nil } // We want to use the superview of the scrollview because using scroll view directly may have some issues.
let originalImageViewFrame = viewToSnap.frame // Preserve previous frame
guard let originalImageViewSuperview = viewToSnap.superview else { return nil } // Preserve previous superview
guard let index = originalImageViewSuperview.subviews.index(of: viewToSnap) else { return nil } // Preserve view hierarchy index
// Now change the frame and put it on the new view
viewToSnap.frame = originalImageViewSuperview.convert(originalImageViewFrame, to: temporaryView)
temporaryView.addSubview(viewToSnap)
// Create snapshot
let croppedImage = snapshotImageFor(view: temporaryView)
// Put everything back the way it was
viewToSnap.frame = originalImageViewFrame // Reset frame
originalImageViewSuperview.insertSubview(viewToSnap, at: index) // Reset superview
temporaryView.removeFromSuperview() // Remove the temporary view
self.croppedImage = croppedImage
return croppedImage
}

此过程有一些缺点,例如在主线程上执行所有操作,但对于您的特定过程,这根本不应该是一个问题。

您可能在某些时候想要对图像输出大小进行一些控制。您可以通过修改快照映像以包含自定义比例来最简单的方法:

func snapshotImageFor(view: UIView, scale: CGFloat = 0.0) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, scale)

然后,例如,您将调用snapshotImageFor(view: view, scale: expectedWidth/view.bounds.width)

最新更新