簡體   English   中英

UIImagePicker 允許編輯卡在中心

[英]UIImagePicker allowsEditing stuck in center

我有一個 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) {
                                 }];
            }
}

如您所見,我將它們顯示為完全相同,但相機編輯的行為與照片庫編輯不同。

看起來這種行為只是iOS 6中的一個錯誤......基本上你不能移動編輯框,除非你放大一點,否則它總是彈回中間。 希望他們能盡快解決這個問題。

謝謝 擴展程序有效。 除了我在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
        }
}

重置contentInsetscrollview

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

這是 Image Picker Controller 的默認行為,您無法更改它。 唯一的其他選擇是創建自己的裁剪實用程序。 查看下面的鏈接以獲取示例:

https://github.com/ardalahmet/SSPhotoCropperViewController

我知道,這不是一個好的解決方案,但它確實有效。

我在iOS8+iPhone5、iOS9+iPhone6sPlus、iOS10+iPhone6、iOS10+iPhone6sPlus上進行了測試。

注意PLImageScrollViewPLCropOverlayCropViewUNDOCUMENTED類。

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

編輯eachSubview:方法遍歷所有子視圖樹。

如果您在 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
    })}

顯然這是相同的解決方法。希望這會有所幫助。

這是我最終使用的一個擴展,它在缺口和非缺口設備上都可以正常工作。 在 iOS 15 上完美運行!

extension UIImagePickerController {
    open override var childForStatusBarHidden: UIViewController? {
        return nil
    }

    open override var prefersStatusBarHidden: Bool {
        return true
    }
    
    open override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        fixCannotMoveEditingBox()
    }
    
    private func fixCannotMoveEditingBox() {
        if let cropView = cropView, let scrollView = scrollView, scrollView.contentOffset.y == 0 {
            let top: CGFloat = cropView.frame.minY + self.view.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()
        }
    }
    
    private var cropView: UIView? {
        return findCropView(from: self.view)
    }
    
    private var scrollView: UIScrollView? {
        return findScrollView(from: self.view)
    }
    
    private 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
    }
    
    private 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
    }
}

ps:與其他類似答案的唯一變化是:

  • 放棄對舊 iOS 版本(如 iOS 11)的支持;
  • 計算 contentInset 頂部屬性的方式有點不同;

解決它的一種解決方法是在 info.plist 中添加一個條目,並將“基於控制器的狀態欄外觀”設置為 NO

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM