可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a UIImagePicker that works perfect for a type of UIImagePickerControllerSourceTypePhotoLibrary, but when I use UIImagePickerControllerSourceTypeCamera, the editing box cannot move from the center of the image. So if the image is say taller than it is wide, the user cannot move the editing box to the top square of the image.
Anyone know why this would be the case? It only happens when the source is from the camera, not the library.
Edit: Some CODE!!!
if (actionSheet.tag == 2) {
if (buttonIndex == 0) { // Camera
// Check for camera
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == YES) {
// Create image picker controller
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
// Set source to the camera
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.allowsEditing = YES;
// Delegate is self
imagePicker.delegate = self;
// Show image picker
[self presentViewController:imagePicker
animated:YES
completion:^(void) {
}];
}
}
else if (buttonIndex == 1) { // Photo Library
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] == YES) {
// Create image picker controller
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
// Set source to the camera
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePicker.allowsEditing = YES;
// Delegate is self
imagePicker.delegate = self;
// Show image picker
[self presentViewController:imagePicker
animated:YES
completion:^(void) {
}];
}
}
So as you can see, I display them the exact same, but the camera edit acts differently than the photo library edit.
回答1:
Looks like this behavior is just a bug in iOS 6... Basically you cannot move the editing box, it always bounces back to the middle unless you zoom in a bit. Hopefully they fix that soon.
回答2:
This is the default behavior the Image Picker Controller, you can not change it. The only other option is to create your own cropping utility. Check out the link below for an example:
https://github.com/ardalahmet/SSPhotoCropperViewController
回答3:
I know, this is not a good solution, but it works.
I tested on iOS8+iPhone5, iOS9+iPhone6sPlus, iOS10+iPhone6, iOS10+iPhone6sPlus.
CAUTION: PLImageScrollView
and PLCropOverlayCropView
are UNDOCUMENTED classes.
- (void)showImagePickerControllerWithSourceType:(UIImagePickerControllerSourceType)sourceType {
UIImagePickerController *imagePickerController = [UIImagePickerController new];
imagePickerController.sourceType = sourceType;
imagePickerController.mediaTypes = @[(NSString *)kUTTypeImage];
imagePickerController.allowsEditing = YES;
imagePickerController.delegate = self;
[self presentViewController:imagePickerController animated:YES completion:^{
[self fxxxImagePickerController:imagePickerController];
}];
}
- (void)fxxxImagePickerController:(UIImagePickerController *)imagePickerController {
if (!imagePickerController
|| !imagePickerController.allowsEditing
|| imagePickerController.sourceType != UIImagePickerControllerSourceTypeCamera) {
return;
}
// !!!: UNDOCUMENTED CLASS
Class ScrollViewClass = NSClassFromString(@"PLImageScrollView");
Class CropViewClass = NSClassFromString(@"PLCropOverlayCropView");
[imagePickerController.view eachSubview:^BOOL(UIView *subview, NSInteger depth) {
if ([subview isKindOfClass:CropViewClass]) {
// 0. crop rect position
subview.frame = subview.superview.bounds;
}
else if ([subview isKindOfClass:[UIScrollView class]]
&& [subview isKindOfClass:ScrollViewClass]) {
BOOL isNewImageScrollView = !self->_imageScrollView;
self->_imageScrollView = (UIScrollView *)subview;
// 1. enable scrolling
CGSize size = self->_imageScrollView.frame.size;
CGFloat inset = ABS(size.width - size.height) / 2;
self->_imageScrollView.contentInset = UIEdgeInsetsMake(inset, 0, inset, 0);
// 2. centering image by default
if (isNewImageScrollView) {
CGSize contentSize = self->_imageScrollView.contentSize;
if (contentSize.height > contentSize.width) {
CGFloat offset = round((contentSize.height - contentSize.width) / 2 - inset);
self->_imageScrollView.contentOffset = CGPointMake(self->_imageScrollView.contentOffset.x, offset);
}
}
}
return YES;
}];
// prevent re-layout, maybe not necessary
@weakify(self, imagePickerController);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
@strongify(self, imagePickerController);
[self fxxxImagePickerController:imagePickerController];
});
}
EDIT: The eachSubview:
method traverses all the subviews tree.
回答4:
If you have set "View controller-based status bar appearance" to NO in info.plist and set status bar appearance as light using
UIApplication.shared.statusBarStyle = .lightContent
or using any other method , Then simply set the style as .default before presenting the image picker. for Eg:
imagePicker.allowsEditing = true
imagePicker.sourceType = .photoLibrary
UIApplication.shared.statusBarStyle = .default
present(imagePicker, animated: true, completion: nil)
Change the source type according to your need either as photoLibrary or camera and in completion block of your didFinishPickingMediaWithInfo add the following to completion block.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
//let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
var pickedImage : UIImage?
if let img = info[UIImagePickerControllerEditedImage] as? UIImage
{
pickedImage = img
}
else if let img = info[UIImagePickerControllerOriginalImage] as? UIImage
{
pickedImage = img
}
dismiss(animated: true, completion: {
UIApplication.shared.statusBarStyle = .lightContent
})}
Apparently this is a workaround for the same.Hope this helps.
回答5:
Stupid answer
Reset contentInset of scrollview
#import <objc/runtime.h>
@interface WeakObjectContainer : NSObject
@property (nonatomic, readonly, weak) id object;
@end
@implementation WeakObjectContainer
- (instancetype) initWithObject:(id)object
{
if (!(self = [super init]))
return nil;
_object = object;
return self;
}
@end
@implementation UIImagePickerController (PLUS)
// MARK: - Create a weak stored property in extension
- (id)weakObjectForKey:(const void*)key {
WeakObjectContainer *container = objc_getAssociatedObject(self, key);
return [container object];
}
- (void)setWeakObject:(id)object forKey:(const void*)key {
WeakObjectContainer *container = [[WeakObjectContainer alloc] initWithObject:object];
objc_setAssociatedObject(self, key, container, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
// MARK: - Create a weak property for scrollView
- (UIScrollView *)scrollView {
return [self weakObjectForKey:_cmd];
}
- (void)setScrollView:(UIScrollView *)scrollView {
[self setWeakObject:scrollView forKey:@selector(scrollView)];
}
// MARK: - Create a weak property for cropView
- (UIView *)cropView {
return [self weakObjectForKey:_cmd];
}
- (void)setCropView:(UIView *)cropView {
[self setWeakObject:cropView forKey:@selector(cropView)];
}
// MARK: - Fix cannot move editing xox
- (void)fixCannotMoveEditingBox {
if (!self.scrollView || !self.cropView) {
UIView *view = [self view];
self.scrollView = [self findScrollView:view];
self.cropView = [self findCropView:view];
if (self.scrollView && self.cropView) {
CGFloat top = self.cropView.frame.origin.y;
CGFloat bottom = ({
self.scrollView.frame.size.height - self.cropView.frame.size.height - self.cropView.frame.origin.y;
});
self.scrollView.contentInset = UIEdgeInsetsMake(top, 0, bottom, 0);
self.scrollView.contentOffset = CGPointMake(0, -1);
}
}
__weak typeof(self) weakself = self;
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC);
dispatch_after(delay, dispatch_get_main_queue(), ^(void){
__strong typeof(weakself) strongself = weakself;
[strongself fixCannotMoveEditingBox];
});
}
- (UIScrollView *)findScrollView:(UIView *)view {
if ([view isKindOfClass:[UIScrollView class]]) {
return (UIScrollView *)view;
}
for (UIView *subview in [view subviews]) {
UIScrollView *view = [self findScrollView:subview];
if (view) {
return view;
}
}
return nil;
}
- (UIView *)findCropView:(UIView *)view {
CGFloat width = [[UIScreen mainScreen] bounds].size.width;
CGSize size = [view frame].size;
if (size.width == width && size.height == width) {
return view;
}
for (UIView *subview in [view subviews]) {
UIView *view = [self findCropView:subview];
if (view) {
return view;
}
}
return nil;
}
@end
then call it
[imagePickerController fixCannotMoveEditingBox];
回答6:
A workaround that solved it is to add an entry in info.plist with "View controller-based status bar appearance" set to NO