iOS Custom UIImagePickerController Camera Crop to circle - in preview view

后端 未结 4 657
花落未央
花落未央 2020-12-20 08:45

I\'m using this code to make a custom camera crop:

UIImagePickerController editing view circle overlay

This works perfectly in camera roll but not taking pho

4条回答
  •  轮回少年
    2020-12-20 09:20

    Although I believe that my reply might be too late, I ended it up mixing my solution with this one: https://gist.github.com/hamin/e8c6dfe00d9c81375f3e, where:

    1. In order to get overlay working properly on Camera, I was listening to notifications (taken & rejecting picture) due to add or remove circle overlay

    2. Kept the solution mentioned above where I need to loop through UINavigationController and draw circle overlay when it was requested to.

    To sum up, please find below my solution written in Swift:

    public class CustomPicture: NSObject {
    //MARK: - Properties
    private var myPickerController: UIImagePickerController?
    private var plCropOverlayBottomBar: UIView?
    private var customLayer: CAShapeLayer?
    
    //MARK: - Constants
    private let screenHeight = UIScreen.mainScreen().bounds.size.height
    private let screenWidth = UIScreen.mainScreen().bounds.size.width
    private let kCameraNotificationIrisAnimationEnd = "_UIImagePickerControllerUserDidCaptureItem"
    private let kCameraNotificationUserRejection = "_UIImagePickerControllerUserDidRejectItem"
    private let kPUUIImageViewController = "PUUIImageViewController"
    private let kPLUIImageViewController = "PLUIImageViewController"
    private let kPLCropOverlayCropView = "PLCropOverlayCropView"
    private let kPLCropOverlayBottomBar = "PLCropOverlayBottomBar"
    
    //MARK: - Overrides
    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    
    //MARK: - Privates
    private func camera() {
        listenToCameraNotifications()
        let myPickerController = UIImagePickerController()
    
        myPickerController.delegate = self
        myPickerController.sourceType = .Camera
        myPickerController.allowsEditing = true
    
        self.myPickerController = myPickerController
    
        self.navigationController?.presentViewController(myPickerController, animated: true, completion: nil)
    }
    
    private func listenToCameraNotifications() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(cameraNotificationIrisEnd), name: kCameraNotificationIrisAnimationEnd, object: nil)
    
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(cameraNotificationRejected), name: kCameraNotificationUserRejection, object: nil)
    }
    
    private func photoLibrary() {
        let myPickerController = UIImagePickerController()
    
        myPickerController.delegate = self
        myPickerController.allowsEditing = true
        myPickerController.sourceType = .PhotoLibrary
    
        self.myPickerController = myPickerController
    
        self.navigationController?.presentViewController(myPickerController, animated: true, completion: nil)
    }
    
    //MARK: - Selector
    /**
     Listen to notification sent after reject button has been touched
     */
    func cameraNotificationRejected() {
        customLayer!.removeFromSuperlayer()
        plCropOverlayBottomBar!.removeFromSuperview()
    }
    
    /**
     Listen to notification sent after picture has been taken
     */
    func cameraNotificationIrisEnd() {
        addCircleOverlay(viewController: self.myPickerController!)
    }
    }
    
    extension CustomPicture: UINavigationControllerDelegate {
    //MARK: - Override
    public func navigationController(navigationController: UINavigationController, willShowViewController: UIViewController, animated: Bool) {
        if isImageViewer(navigationController: navigationController) {
            addCircleOverlay(viewController: willShowViewController)
        }
    }
    
    //MARK: - Private
    private func addCircleOverlay(viewController viewController: UIViewController) {
        hidePLCropOverlay(view: viewController.view)
        setPLCropOverlayBottomBar(view: viewController.view)
        setCustomLayer(viewController: viewController)
    }
    
    private func getCirclePath() -> UIBezierPath {
        let circlePath = UIBezierPath(ovalInRect: CGRectMake(0, screenHeight / 2 - screenWidth / 2, screenWidth, screenWidth))
        circlePath.usesEvenOddFillRule = true
    
        let circleLayer = CAShapeLayer()
        circleLayer.path = circlePath.CGPath
        circleLayer.fillColor = UIColor.clearColor().CGColor
    
        return circlePath
    }
    
    private func getMaskPath(screenWidth screenWidth: CGFloat, screenHeight: CGFloat, circlePath: UIBezierPath) -> UIBezierPath {
        let maskPath = UIBezierPath(roundedRect: CGRectMake(0, 0, screenWidth, screenHeight), cornerRadius: 0)
        maskPath.appendPath(circlePath)
        maskPath.usesEvenOddFillRule = true
    
        return maskPath
    }
    
    private func hidePLCropOverlay(view view: UIView) {
        for myView in view.subviews {
            if myView.isKindOfClass(NSClassFromString(kPLCropOverlayCropView)!) {
                myView.hidden = true
                break
            } else {
                hidePLCropOverlay(view: myView as UIView)
            }
        }
    }
    
    private func isImageViewer(navigationController navigationController: UINavigationController) -> Bool {
        if (navigationController.viewControllers.count == 3 &&
            (navigationController.viewControllers[2].dynamicType.description() == kPUUIImageViewController ||
                navigationController.viewControllers[2].dynamicType.description() == kPLUIImageViewController)) {
    
            return true
        }
    
        return false
    }
    
    private func setPLCropOverlayBottomBar(view view: UIView) {
        for myView in view.subviews {
            if myView.isKindOfClass(NSClassFromString(kPLCropOverlayBottomBar)!) {
                plCropOverlayBottomBar = myView
                break
            }
            else {
                savePLCropOverlayBottomBar(view: myView as UIView)
            }
        }
    }
    
    private func setCustomLayer(viewController viewController: UIViewController) {
        let circlePath = getCirclePath()
        let maskPath = getMaskPath(screenWidth: screenWidth, screenHeight: screenHeight, circlePath: circlePath)
        let maskLayer = CAShapeLayer()
        maskLayer.path = maskPath.CGPath
        maskLayer.fillRule = kCAFillRuleEvenOdd
        maskLayer.fillColor = UIColor.blackColor().colorWithAlphaComponent(0.8).CGColor
        customLayer = maskLayer
    
        viewController.view.layer.addSublayer(customLayer!)
        viewController.view.addSubview(plCropOverlayBottomBar!) // put back overlayBottomBar once we set its parent to hidden (subview of PLCropOverlay)
    }
    }
    

提交回复
热议问题