【问题标题】:UIImagePicker allowsEditing stuck in centerUIImagePicker 允许编辑卡在中心
【发布时间】: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) {
                                 }];
            }
}

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

【问题讨论】:

    标签: iphone ios uiimagepickercontroller


    【解决方案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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-06-11
              • 1970-01-01
              • 2015-05-21
              • 1970-01-01
              • 2013-08-10
              相关资源
              最近更新 更多