UIImagePicker 允许编辑卡在中心

Posted

技术标签:

【中文标题】UIImagePicker 允许编辑卡在中心【英文标题】:UIImagePicker allowsEditing stuck in center 【发布时间】:2012-09-27 21:16:43 【问题描述】:

我有一个 UIImagePicker,它非常适合一种 UIImagePickerControllerSourceTypePhotoLibrary,但是当我使用 UIImagePickerControllerSourceTypeCamera 时,编辑框无法从图像的中心移动。因此,如果图像的高度大于宽度,则用户无法将编辑框移动到图像的顶部正方形。

有人知道为什么会这样吗?只有当源来自相机而不是库时才会发生这种情况。

编辑:一些代码!!!

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) 
                                 ];
            

如您所见,我将它们显示为完全相同,但相机编辑与照片库编辑的行为不同。

【问题讨论】:

【参考方案1】:

看起来这种行为只是ios 6中的一个错误......基本上你不能移动编辑框,除非你放大一点,它总是弹回中间。希望他们能尽快解决这个问题。

【讨论】:

我认为这仍然是 iOS 7 中的一个错误 aaa 仍然是 iOS 8 中的一个错误。:( iOS 8.1 也存在同样的 bug 我来自未来,仍然是 iOS 12.0 中的一个 bug 仍然是 iOS 9 中的一个错误。有人找到解决方案了吗?【参考方案2】:

谢谢yycking。这extension 有效。除了我在viewDidLayoutSubviews 中添加了方法调用,这样我就不必每次打开图像选择器时都调用它。

这是完整的扩展名

extension UIImagePickerController 
    open override var childForStatusBarHidden: UIViewController? 
        return nil
    

    open override var prefersStatusBarHidden: Bool 
        return true
    
    
    open override func viewDidLayoutSubviews() 
        super.viewDidLayoutSubviews()
        fixCannotMoveEditingBox()
    
    
    func fixCannotMoveEditingBox() 
            if let cropView = cropView,
               let scrollView = scrollView,
               scrollView.contentOffset.y == 0 
                
                var top: CGFloat = 0.0
                if #available(iOS 11.0, *) 
                    top = cropView.frame.minY + self.view.safeAreaInsets.top
                 else 
                    // Fallback on earlier versions
                    top = cropView.frame.minY
                
                let bottom = scrollView.frame.height - cropView.frame.height - top
                scrollView.contentInset = UIEdgeInsets(top: top, left: 0, bottom: bottom, right: 0)
                
                var offset: CGFloat = 0
                if scrollView.contentSize.height > scrollView.contentSize.width 
                    offset = 0.5 * (scrollView.contentSize.height - scrollView.contentSize.width)
                
                scrollView.contentOffset = CGPoint(x: 0, y: -top + offset)
            
            
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1)  [weak self] in
                self?.fixCannotMoveEditingBox()
            
        
        
        var cropView: UIView? 
            return findCropView(from: self.view)
        
        
        var scrollView: UIScrollView? 
            return findScrollView(from: self.view)
        
        
        func findCropView(from view: UIView) -> UIView? 
            let width = UIScreen.main.bounds.width
            let size = view.bounds.size
            if width == size.height, width == size.height 
                return view
            
            for view in view.subviews 
                if let cropView = findCropView(from: view) 
                    return cropView
                
            
            return nil
        
        
        func findScrollView(from view: UIView) -> UIScrollView? 
            if let scrollView = view as? UIScrollView 
                return scrollView
            
            for view in view.subviews 
                if let scrollView = findScrollView(from: view) 
                    return scrollView
                
            
            return nil
        

【讨论】:

【参考方案3】:

愚蠢的答案 重置scrollview的contentInset

extension UIImagePickerController 
    func fixCannotMoveEditingBox() 
        if let cropView = cropView,
           let scrollView = scrollView,
           scrollView.contentOffset.y == 0 
            
            let top = cropView.frame.minY + self.view.safeAreaInsets.top
            let bottom = scrollView.frame.height - cropView.frame.height - top
            scrollView.contentInset = UIEdgeInsets(top: top, left: 0, bottom: bottom, right: 0)
            
            var offset: CGFloat = 0
            if scrollView.contentSize.height > scrollView.contentSize.width 
                offset = 0.5 * (scrollView.contentSize.height - scrollView.contentSize.width)
            
            scrollView.contentOffset = CGPoint(x: 0, y: -top + offset)
        
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1)  [weak self] in
            self?.fixCannotMoveEditingBox()
        
    
    
    var cropView: UIView? 
        return findCropView(from: self.view)
    
    
    var scrollView: UIScrollView? 
        return findScrollView(from: self.view)
    
    
    func findCropView(from view: UIView) -> UIView? 
        let width = UIScreen.main.bounds.width
        let size = view.bounds.size
        if width == size.height, width == size.height 
            return view
        
        for view in view.subviews 
            if let cropView = findCropView(from: view) 
                return cropView
            
        
        return nil
    
    
    func findScrollView(from view: UIView) -> UIScrollView? 
        if let scrollView = view as? UIScrollView 
            return scrollView
        
        for view in view.subviews 
            if let scrollView = findScrollView(from: view) 
                return scrollView
            
        
        return nil
    

然后调用它

imagePickercontroller.fixCannotMoveEditingBox()

【讨论】:

【参考方案4】:

这是 Image Picker Controller 的默认行为,您不能更改它。唯一的其他选择是创建自己的裁剪实用程序。查看下面的链接以获取示例:

https://github.com/ardalahmet/SSPhotoCropperViewController

【讨论】:

但是当你从专辑中挑选时它会起作用..没有意义。当它来自相册而不是相机时,为什么你可以移动更多 @Eric 编辑框完全不动,它固定在屏幕中间,您可以缩放图片以适应框。截图,因为你的代码是对的 我会尽快添加屏幕截图,但我的意思是静态框保持静止(这是正确的),但移动的下方图像无法移动,因此编辑框位于图像的顶部区域。如果您滚动到该区域,图像会“弹回”到图像的中心... 这不是默认行为,我相信这是 ios6 中的错误。在以前的 ios 版本上它可以正常工作,但在 ios6 上,当您尝试移动它时,图像会反弹回来。但是,如果您放大一点,它确实会起作用。 @Robert 哦,好吧..这就是我的想法!我想我会一直这样,直到他们更新它..【参考方案5】:

我知道,这不是一个好的解决方案,但它确实有效。

我在 iOS8+iPhone5、iOS9+iPhone6sPlus、iOS10+iPhone6、iOS10+iPhone6sPlus 上进行了测试。

注意PLImageScrollViewPLCropOverlayCropView未记录 类。

- (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];
    );


EDITeachSubview: 方法遍历所有子视图树。

【讨论】:

【参考方案6】:

如果您在 info.plist 中将“基于控制器的状态栏外观”设置为 NO,并使用以下方法将状态栏外观设置为浅色

 UIApplication.shared.statusBarStyle = .lightContent

或使用任何其他方法,然后只需在呈现图像选择器之前将样式设置为 .default。例如:

imagePicker.allowsEditing = true
imagePicker.sourceType = .photoLibrary
UIApplication.shared.statusBarStyle = .default
present(imagePicker, animated: true, completion: nil)

根据您的需要将源类型更改为 photoLibrary 或相机,并在 didFinishPickingMediaWithInfo 的完成块中将以下内容添加到完成块中。

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
    )

显然这是一个解决方法。希望这会有所帮助。

【讨论】:

【参考方案7】:

解决此问题的解决方法是在 info.plist 中添加一个条目,并将“基于控制器的状态栏外观”设置为 NO

【讨论】:

以上是关于UIImagePicker 允许编辑卡在中心的主要内容,如果未能解决你的问题,请参考以下文章

UIImagePicker 设置多个图像视图

UIImagePicker 无法在 iOS 3.1.3 上执行全屏转换

iPad 问题:使用 UIImagePicker 从视频文件夹中选择视频

在选项卡式 UIPopover 中使用 UIImagePicker

测试 UIImagePicker

在 iPhone 上的 UIImagePicker 中重新调整图像大小