Reputation: 2497
I am having an issue with the UIImagePickerController
, I have enabled editing, but what is happening is when the user crops the image, there is a y offset between what the square crop shows the user will be the crop, and what the actual crop is. It only works out at about 20 pixels, but is now a big issue. I have included two screenshots that demonstrate the issue. In the first, the crop square seems to extend above the image, but when the inage is chosen the top of the image is set properly (the image is just a screenshot so the top of the image is the top of the status bar). In the second screenshot, if you try and put the crop to then very bottom of the photo, it springs back to this position, so the user thinks the bottom of the image is not included, when in fact it is, when it is chosen. Bit of a headache. Seems to do the same in the simulator as on device. Anyone know why this might be?
Upvotes: 5
Views: 1463
Reputation: 714
For anyone who has a similar problem.
I had a issue with images having a black line at the top of photo when allowEditing
was set to true. I was testing this on iPhone 11, iOS 14.
I've discovered that the cause for this was setting a different modalPresentationStyle
of UIImagePickerViewController
. Once I removed this line:
picker.modalPresentationStyle = .overFullScreen
edited image retrieved in delegate method has correct size.
Upvotes: 0
Reputation: 83
I have recently come across this issue. Here is what fixed it for me:
extension UIImagePickerController {
open override var childForStatusBarHidden: UIViewController? {
return nil
}
open override var prefersStatusBarHidden: Bool {
return true
}
}
"View controller-based status bar appearance" in plist must be YES, otherwise the above code will not be called.
Upvotes: 0
Reputation: 17882
The issue is with the status bar showing on newer devices, it messes with the crop offset in unpredictable ways. To fix all of this easily, simply:
1. Add the following property to your current ViewController:
@property BOOL hideStatusBar;
2. Add the following methods to your current ViewController:
-(BOOL)prefersStatusBarHidden {
return _hideStatusBar;
}
-(UIViewController *)childViewControllerForStatusBarHidden {
return nil;
}
3. Add the following to the method file where you display your imagePicker. Also add UINavigationControllerDelegate to the .h file.
(Note: you likely already have these methods declared so just add the snippets inside them)
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
YourCurrentViewController.hideStatusBar = YES;
[YourCurrentViewController setNeedsStatusBarAppearanceUpdate];
[navigationController setNeedsStatusBarAppearanceUpdate];
//The rest of your code here
//!IMPORTANT: ENSURE YOU'VE ADDED <UINavigationControllerDelegate> IN YOUR .H FILE
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
YourCurrentViewController.hideStatusBar = NO;
[YourCurrentViewController setNeedsStatusBarAppearanceUpdate];
//The rest of your code here
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
YourCurrentViewController.hideStatusBar = NO;
[YourCurrentViewController setNeedsStatusBarAppearanceUpdate];
//The rest of your code here
}
Now the status bar will hide when you launch your imagePicker and will re-appear after you are done picking an image or cancel. With the status bar hiding, the crop offsets will get calculated properly on Apple's end and your edited photo will be correctly cropped!
Upvotes: 0
Reputation: 10002
This doesn't solve the display issue where it shows the cropping box 20px off, but you can side-step the final-cropped image bug by doing the following when the user selects an image:
// MARK: - UIImagePickerControllerDelegate
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: { [weak self] in self?.didCompleteSelection(image: nil) })
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
picker.dismiss(animated: true, completion: { [weak self] in
guard
let originalImage = info[UIImagePickerControllerOriginalImage] as? UIImage,
let cropRect = info[UIImagePickerControllerCropRect] as? CGRect
else { return }
//crop with status-bar offset due to iOS bug introduced in iOS 8 with status bar offset
let offsetRect = cropRect.offsetBy(dx: 0, dy: UIApplication.shared.statusBarFrame.size.height)
guard let croppedImage = originalImage.cgImage?.cropping(to: offsetRect) else { return }
self?.didCompleteSelection?(image: croppedImage)
})
}
Upvotes: 2